1
/******************************************************************************
2
* versemgr.cpp - implementation of class VerseMgr used for managing
3
* versification systems
5
* $Id: versemgr.cpp 2108 2007-10-13 20:35:02Z scribe $
7
* Copyright 1998 CrossWire Bible Society (http://www.crosswire.org)
8
* CrossWire Bible Society
10
* Tempe, AZ 85280-2528
12
* This program is free software; you can redistribute it and/or modify it
13
* under the terms of the GNU General Public License as published by the
14
* Free Software Foundation version 2.
16
* This program is distributed in the hope that it will be useful, but
17
* WITHOUT ANY WARRANTY; without even the implied warranty of
18
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19
* General Public License for more details.
27
#include <canon.h> // KJV internal versification system
31
#include <canon_null.h> // null v11n system
33
#include <canon_leningrad.h> // Leningrad Codex (WLC) v11n system
34
#include <canon_mt.h> // Masoretic Text (MT) v11n system
35
#include <canon_kjva.h> // KJV + Apocrypha v11n system
36
#include <canon_nrsv.h> // NRSV v11n system
37
#include <canon_nrsva.h> // NRSVA + Apocrypha v11n system
42
using std::lower_bound;
47
VerseMgr *VerseMgr::getSystemVerseMgr() {
48
if (!systemVerseMgr) {
49
systemVerseMgr = new VerseMgr();
50
systemVerseMgr->registerVersificationSystem("KJV", otbooks, ntbooks, vm);
51
systemVerseMgr->registerVersificationSystem("Leningrad", otbooks_leningrad, ntbooks_null, vm_leningrad);
52
systemVerseMgr->registerVersificationSystem("MT", otbooks_mt, ntbooks_null, vm_mt);
53
systemVerseMgr->registerVersificationSystem("KJVA", otbooks_kjva, ntbooks, vm_kjva);
54
systemVerseMgr->registerVersificationSystem("NRSV", otbooks, ntbooks, vm_nrsv);
55
systemVerseMgr->registerVersificationSystem("NRSVA", otbooks_nrsva, ntbooks, vm_nrsva);
57
return systemVerseMgr;
61
class VerseMgr::System::Private {
63
/** Array[chapmax] of maximum verses in chapters */
65
map<SWBuf, int> osisLookup;
69
Private(const VerseMgr::System::Private &other) {
71
osisLookup = other.osisLookup;
73
VerseMgr::System::Private &operator =(const VerseMgr::System::Private &other) {
75
osisLookup = other.osisLookup;
81
class VerseMgr::Book::Private {
82
friend struct BookOffsetLess;
84
/** Array[chapmax] of maximum verses in chapters */
86
vector<long> offsetPrecomputed;
91
Private(const VerseMgr::Book::Private &other) {
93
verseMax = other.verseMax;
94
offsetPrecomputed = other.offsetPrecomputed;
96
VerseMgr::Book::Private &operator =(const VerseMgr::Book::Private &other) {
98
verseMax = other.verseMax;
99
offsetPrecomputed = other.offsetPrecomputed;
104
struct BookOffsetLess {
105
bool operator() (const VerseMgr::Book &o1, const VerseMgr::Book &o2) const { return o1.p->offsetPrecomputed[0] < o2.p->offsetPrecomputed[0]; }
106
bool operator() (const long &o1, const VerseMgr::Book &o2) const { return o1 < o2.p->offsetPrecomputed[0]; }
107
bool operator() (const VerseMgr::Book &o1, const long &o2) const { return o1.p->offsetPrecomputed[0] < o2; }
108
bool operator() (const long &o1, const long &o2) const { return o1 < o2; }
111
void VerseMgr::Book::init() {
115
void VerseMgr::System::init() {
123
VerseMgr::System::System(const System &other) {
126
BMAX[0] = other.BMAX[0];
127
BMAX[1] = other.BMAX[1];
129
ntStartOffset = other.ntStartOffset;
132
VerseMgr::System &VerseMgr::System::operator =(const System &other) {
134
BMAX[0] = other.BMAX[0];
135
BMAX[1] = other.BMAX[1];
137
ntStartOffset = other.ntStartOffset;
142
VerseMgr::System::~System() {
146
const VerseMgr::Book *VerseMgr::System::getBook(int number) const {
147
return (number < (signed int)p->books.size()) ? &(p->books[number]) : 0;
151
int VerseMgr::System::getBookNumberByOSISName(const char *bookName) const {
152
map<SWBuf, int>::const_iterator it = p->osisLookup.find(bookName);
153
return (it != p->osisLookup.end()) ? it->second : -1;
157
void VerseMgr::System::loadFromSBook(const sbook *ot, const sbook *nt, int *chMax) {
160
long offset = 0; // module heading
161
offset++; // testament heading
162
while (ot->chapmax) {
163
p->books.push_back(Book(ot->name, ot->osis, ot->prefAbbrev, ot->chapmax));
164
offset++; // book heading
165
Book &b = p->books[p->books.size()-1];
166
p->osisLookup[b.getOSISName()] = p->books.size();
167
for (int i = 0; i < ot->chapmax; i++) {
168
b.p->verseMax.push_back(chMax[chap]);
169
offset++; // chapter heading
170
b.p->offsetPrecomputed.push_back(offset);
171
offset += chMax[chap++];
178
ntStartOffset = offset;
179
offset++; // testament heading
180
while (nt->chapmax) {
181
p->books.push_back(Book(nt->name, nt->osis, nt->prefAbbrev, nt->chapmax));
182
offset++; // book heading
183
Book &b = p->books[p->books.size()-1];
184
p->osisLookup[b.getOSISName()] = p->books.size();
185
for (int i = 0; i < nt->chapmax; i++) {
186
b.p->verseMax.push_back(chMax[chap]);
187
offset++; // chapter heading
188
b.p->offsetPrecomputed.push_back(offset);
189
offset += chMax[chap++];
196
// TODO: build offset speed array
200
VerseMgr::Book::Book(const Book &other) {
201
longName = other.longName;
202
osisName = other.osisName;
203
prefAbbrev = other.prefAbbrev;
204
chapMax = other.chapMax;
209
VerseMgr::Book& VerseMgr::Book::operator =(const Book &other) {
210
longName = other.longName;
211
osisName = other.osisName;
212
prefAbbrev = other.prefAbbrev;
213
chapMax = other.chapMax;
220
VerseMgr::Book::~Book() {
225
int VerseMgr::Book::getVerseMax(int chapter) const {
227
return (p && (chapter < (signed int)p->verseMax.size()) && (chapter > -1)) ? p->verseMax[chapter] : -1;
231
int VerseMgr::System::getBookCount() const {
232
return (p ? p->books.size() : 0);
236
long VerseMgr::System::getOffsetFromVerse(int book, int chapter, int verse) const {
240
const Book *b = getBook(book);
242
if (!b) return -1; // assert we have a valid book
243
if ((chapter > -1) && (chapter >= (signed int)b->p->offsetPrecomputed.size())) return -1; // assert we have a valid chapter
245
offset = b->p->offsetPrecomputed[(chapter > -1)?chapter:0];
246
if (chapter < 0) offset--;
250
offset = offsets[testament-1][0][book];
251
offset = offsets[testament-1][1][(int)offset + chapter];
252
if (!(offset|verse)) // if we have a testament but nothing else.
257
return (offset + verse);
261
char VerseMgr::System::getVerseFromOffset(long offset, int *book, int *chapter, int *verse) const {
263
if (offset < 1) { // just handle the module heading corner case up front (and error case)
267
return offset; // < 0 = error
270
// binary search for book
271
vector<Book>::iterator b = lower_bound(p->books.begin(), p->books.end(), offset, BookOffsetLess());
272
if (b == p->books.end()) b--;
273
(*book) = distance(p->books.begin(), b)+1;
274
if (offset < (*(b->p->offsetPrecomputed.begin()))-((((!(*book)) || (*book)==BMAX[0]+1))?2:1)) { // -1 for chapter headings
276
if (b != p->books.begin()) {
280
vector<long>::iterator c = lower_bound(b->p->offsetPrecomputed.begin(), b->p->offsetPrecomputed.end(), offset);
282
// if we're a book heading, we are lessthan chapter precomputes, but greater book. This catches corner case.
283
if (c == b->p->offsetPrecomputed.end()) {
286
if ((offset < *c) && (c == b->p->offsetPrecomputed.begin())) {
287
(*chapter) = (offset - *c)+1; // should be 0 or -1 (for testament heading)
291
if (offset < *c) c--;
292
(*chapter) = distance(b->p->offsetPrecomputed.begin(), c)+1;
293
(*verse) = (offset - *c);
295
return ((*chapter > 0) && (*verse > b->getVerseMax(*chapter))) ? KEYERR_OUTOFBOUNDS : 0;
299
/***************************************************
303
class VerseMgr::Private {
307
Private(const VerseMgr::Private &other) {
308
systems = other.systems;
310
VerseMgr::Private &operator =(const VerseMgr::Private &other) {
311
systems = other.systems;
314
map<SWBuf, System> systems;
316
// ---------------- statics -----------------
317
VerseMgr *VerseMgr::systemVerseMgr = 0;
319
class __staticsystemVerseMgr {
321
__staticsystemVerseMgr() { }
322
~__staticsystemVerseMgr() { delete VerseMgr::systemVerseMgr; }
323
} _staticsystemVerseMgr;
326
void VerseMgr::init() {
331
VerseMgr::~VerseMgr() {
336
void VerseMgr::setSystemVerseMgr(VerseMgr *newVerseMgr) {
338
delete systemVerseMgr;
339
systemVerseMgr = newVerseMgr;
343
const VerseMgr::System *VerseMgr::getVersificationSystem(const char *name) const {
344
map<SWBuf, System>::const_iterator it = p->systems.find(name);
345
return (it != p->systems.end()) ? &(it->second) : 0;
349
void VerseMgr::registerVersificationSystem(const char *name, const sbook *ot, const sbook *nt, int *chMax) {
350
p->systems[name] = name;
351
System &s = p->systems[name];
352
s.loadFromSBook(ot, nt, chMax);
356
void VerseMgr::registerVersificationSystem(const char *name, const TreeKey *tk) {
360
const StringList VerseMgr::getVersificationSystems() const {
362
for (map<SWBuf, System>::const_iterator it = p->systems.begin(); it != p->systems.end(); it++) {
363
retVal.push_back(it->first);