diff options
author | Your Name <you@example.com> | 2020-11-05 15:50:11 -0500 |
---|---|---|
committer | Your Name <you@example.com> | 2020-11-05 15:50:11 -0500 |
commit | 2fe897e2cf750339a7e466aeafe64f45fb650f10 (patch) | |
tree | d27bbda7c1ef5368a90704843deea014e6c810de /libbible.cc | |
download | libbible-2fe897e2cf750339a7e466aeafe64f45fb650f10.tar.gz libbible-2fe897e2cf750339a7e466aeafe64f45fb650f10.tar.bz2 libbible-2fe897e2cf750339a7e466aeafe64f45fb650f10.zip |
Initial commit
Diffstat (limited to 'libbible.cc')
-rw-r--r-- | libbible.cc | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/libbible.cc b/libbible.cc new file mode 100644 index 0000000..7b08174 --- /dev/null +++ b/libbible.cc @@ -0,0 +1,218 @@ +#include "libbible.h" +#include <sword/versekey.h> +#include <sword/markupfiltmgr.h> +#include <sword/swmodule.h> +#include <sword/swmgr.h> +#include <algorithm> + +using namespace sword; +using namespace std; + +SWMgr library(new MarkupFilterMgr(FMT_XHTML)); + +vector<string> getBooks(SWModule *target) { + vector<string> books; + VerseKey *key = (VerseKey *) target->getKey(); + for(char t = 1; t <= key->getTestamentMax(); t++) { + key->setTestament(t); + for(char b = 1; b <= key->getBookMax(); b++) { + key->setBook(b); + // Bug (whose fault??) in JPS; they CLAIM to have two testaments, + // but they only have one, which causes repeats. + if(std::find(books.begin(), books.end(), key->getBookName()) == books.end()) { + books.push_back(key->getBookName()); + } + } + } + return books; +} + +map<string, vector<string>> libbible::getModules() { + library.load(); + map<string, vector<string>> mods; + ModMap::iterator it; + for (it = library.getModules().begin(); it != library.getModules().end(); it++) { + string modName = (*it).second->getName(); + SWModule *target = library.getModule(modName.c_str()); + mods[modName] = getBooks(target); + } + return mods; +} + +vector<libbible::passage> libbible::getPassages(string modName, string book) { + vector<libbible::passage> passages; + SWModule *target = library.getModule(modName.c_str()); + target->setKey((book + " " + "1").c_str()); + VerseKey *key = (VerseKey *) target->getKey(); + int maxChapter = key->getChapterMax(); + for(int chapter = 1; chapter <= maxChapter; chapter++) { + string ref = book + ' ' + to_string(chapter); + target->setKey(ref.c_str()); + VerseKey *key = (VerseKey *) target->getKey(); + libbible::passage pass; + pass.modName = modName; + pass.reference = ref; + pass.book = string(key->getBookName()); + pass.bookShort = string(key->getBookAbbrev()); + pass.chapterStart = chapter; + pass.chapterEnd = chapter; + pass.verseStart = 1; + pass.verseEnd = key->getVerseMax(); + passages.push_back(pass); + } + return passages; +} + +libbible::text getEmptyText(VerseKey *key) { + libbible::text t; + t.chapter = key->getChapter(); + t.verse = key->getVerse(); + t.book = key->getBook(); + t.bookShort = key->getBookAbbrev(); + return t; +} + +void inferMissing(libbible::passage *pass, SWModule *target) { + //printf("Hey, I'm inferring missing parts!\n"); + if(! pass->reference.empty()) { + // Let's use the target to help us + target->setKey(pass->reference.c_str()); + VerseKey *key = (VerseKey *) target->getKey(); + pass->book = string(key->getBookName()); + pass->bookShort = string(key->getBookAbbrev()); + pass->chapterStart = key->getChapter(); + pass->verseStart = key->getVerse(); + //printf("Results so far: book: %s; chapterStart: %d; verseStart: %d\n", pass->book.c_str(), pass->chapterStart, pass->verseStart); + // And now we just need chapterEnd and verseEnd. Yippee. + string ref = string(pass->reference); + ref.erase(remove(ref.begin(), ref.end(), ' '), ref.end()); + if(ref.find('-') == string::npos) { + // There's no range! + if(ref.find(':') == string::npos) { + // It's a full chapter reference + pass->chapterEnd = pass->chapterStart; + pass->verseEnd = key->getVerseMax(); + } else { + // It's a single verse reference + pass->chapterEnd = pass->chapterStart; + pass->verseEnd = pass->verseStart; + //printf("Hey, it's a single verse reference!\n"); + } + } else { + if(ref.find(':') == string::npos) { + // It's a multi-full-chapter reference + pass->chapterEnd = stoi(ref.substr(ref.find_last_of('-')+1)); + pass->verseEnd = key->getVerseMax(); + } else { + // It falls in categories c:v-v or c:v-c:v (or, technically, c-c:v) + string rangeEnd = ref.substr(ref.find_last_of('-')+1); + if(rangeEnd.find(':') == string::npos) { + // It's c:v-v + pass->verseEnd = stoi(rangeEnd); + pass->chapterEnd = pass->chapterStart; + } else { + // It's c:v-c:v (or c-c:v, but code is the same) + pass->chapterEnd = stoi(rangeEnd.substr(0, rangeEnd.find(':'))); + pass->verseEnd = stoi(rangeEnd.substr(rangeEnd.find(':')+1)); + } + } + } + } + if(pass->book.empty()) { + pass->book = pass->bookShort; + } +} + +vector<libbible::text> libbible::getText(libbible::passage pass) { + SWModule *target = library.getModule(pass.modName.c_str()); + inferMissing(&pass, target); + target->setKey((pass.book + + " " + to_string(pass.chapterStart) + + ":" + to_string(pass.verseStart)).c_str()); + VerseKey *key = (VerseKey *) target->getKey(); + vector<libbible::text> texts; + + bool endOfParagraph = false; + + for(; key->getChapter() < pass.chapterEnd || + (key->getChapter() == pass.chapterEnd && key->getVerse() <= pass.verseEnd); + (*key)++) { + texts.push_back(getEmptyText(key)); + + string text = string(target->renderText()); + + // Handle ¶ symbol if at beginning of line + if(text.find("¶") == 0) { + text.replace(0, 1, "\n"); + endOfParagraph = true; + } + + while(text[0] == ' ' || text[0] == '\t') { + text.erase(0, 1); + } + + // Find and replace everything in "subs" map + const map<string, string> subs = {{"¶", "\n\t"}}; + for(auto const &repl : subs) { + string::size_type location; + while((location = text.find(repl.first)) != string::npos) { + text.replace(location, repl.first.size(), repl.second); + } + } + + if(key->getVerse() == 1 || endOfParagraph) { + if(find(texts.back().modifiers.begin(), texts.back().modifiers.end(), "paragraph") == texts.back().modifiers.end()) { + texts.back().modifiers.push_back("paragraph"); + } + endOfParagraph = false; + } + + // Variable to accumulate unterminated spans + std::vector<string> spans; + bool spansChanged = false; + // Iterate over text + for(auto i = text.begin(); i != text.end(); i++) { + if(*i != '<') { + if(spansChanged) { + spansChanged = false; + if(!texts.back().text.empty()) { + texts.push_back(getEmptyText(key)); + } + for(string modifier : spans) { + if(find(texts.back().modifiers.begin(), texts.back().modifiers.end(), modifier) == texts.back().modifiers.end()) { + texts.back().modifiers.push_back(modifier); + } + } + } + texts.back().text += *i; + } + else { + string span; + for(; i != text.end(); i++) { + span.push_back(*i); + if(*i == '>') { + // The end of the span will be "</span>". + if(span == "</span>") { + if(! spans.empty()) { + spans.pop_back(); + spansChanged = true; + } + } else { + // The span will be formatted "<span class=\"NAME\">" + // We want just the NAME + size_t start = span.find_first_of('"')+1; + size_t end = span.find_last_of('"'); + if(start > 0) { + spans.push_back(span.substr(start, end-start)); + spansChanged = true; + } + } + break; + } + } + } + } + endOfParagraph = (text[text.length()-1] == '\n'); + } + return texts; +} |