summaryrefslogtreecommitdiff
path: root/src/mgr
diff options
context:
space:
mode:
Diffstat (limited to 'src/mgr')
-rw-r--r--src/mgr/Makefile.am2
-rw-r--r--src/mgr/curlftpt.cpp20
-rw-r--r--src/mgr/curlhttpt.cpp178
-rw-r--r--src/mgr/encfiltmgr.cpp7
-rw-r--r--src/mgr/filemgr.cpp4
-rw-r--r--src/mgr/ftplibftpt.cpp19
-rw-r--r--src/mgr/ftptrans.cpp23
-rw-r--r--src/mgr/installmgr.cpp262
-rw-r--r--src/mgr/localemgr.cpp33
-rw-r--r--src/mgr/swconfig.cpp52
-rw-r--r--src/mgr/swlocale.cpp104
-rw-r--r--src/mgr/swmgr.cpp253
-rw-r--r--src/mgr/versemgr.cpp369
13 files changed, 1082 insertions, 244 deletions
diff --git a/src/mgr/Makefile.am b/src/mgr/Makefile.am
index 1b1e33b..10d7158 100644
--- a/src/mgr/Makefile.am
+++ b/src/mgr/Makefile.am
@@ -11,6 +11,7 @@ AM_CPPFLAGS += -D_FTPLIB_NO_COMPAT
if WITHCURL
FTP_SOURCES = $(mgrdir)/curlftpt.cpp
+FTP_SOURCES += $(mgrdir)/curlhttpt.cpp
else
FTP_SOURCES = $(mgrdir)/ftplibftpt.cpp
endif
@@ -22,6 +23,7 @@ libsword_la_SOURCES += $(mgrdir)/swfiltermgr.cpp
libsword_la_SOURCES += $(mgrdir)/encfiltmgr.cpp
libsword_la_SOURCES += $(mgrdir)/markupfiltmgr.cpp
libsword_la_SOURCES += $(mgrdir)/filemgr.cpp
+libsword_la_SOURCES += $(mgrdir)/versemgr.cpp
libsword_la_SOURCES += $(mgrdir)/ftptrans.cpp
libsword_la_SOURCES += $(mgrdir)/swlocale.cpp
libsword_la_SOURCES += $(mgrdir)/localemgr.cpp
diff --git a/src/mgr/curlftpt.cpp b/src/mgr/curlftpt.cpp
index bb47958..91d8e82 100644
--- a/src/mgr/curlftpt.cpp
+++ b/src/mgr/curlftpt.cpp
@@ -1,7 +1,24 @@
/*****************************************************************************
* CURLFTPTransport functions
*
+ *
+ *
+ * Copyright 2009 CrossWire Bible Society (http://www.crosswire.org)
+ * CrossWire Bible Society
+ * P. O. Box 2528
+ * Tempe, AZ 85280-2528
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
*/
+
#include <curlftpt.h>
@@ -109,7 +126,8 @@ char CURLFTPTransport::getURL(const char *destPath, const char *sourceURL, SWBuf
if (session) {
curl_easy_setopt(session, CURLOPT_URL, sourceURL);
- curl_easy_setopt(session, CURLOPT_USERPWD, "ftp:installmgr@user.com");
+ SWBuf credentials = u + ":" + p;
+ curl_easy_setopt(session, CURLOPT_USERPWD, credentials.c_str());
curl_easy_setopt(session, CURLOPT_WRITEFUNCTION, my_fwrite);
if (!passive)
curl_easy_setopt(session, CURLOPT_FTPPORT, "-");
diff --git a/src/mgr/curlhttpt.cpp b/src/mgr/curlhttpt.cpp
new file mode 100644
index 0000000..8ddb1cf
--- /dev/null
+++ b/src/mgr/curlhttpt.cpp
@@ -0,0 +1,178 @@
+ /*****************************************************************************
+ * CURLHTTPTransport functions
+ *
+ *
+ *
+ * Copyright 2009 CrossWire Bible Society (http://www.crosswire.org)
+ * CrossWire Bible Society
+ * P. O. Box 2528
+ * Tempe, AZ 85280-2528
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ */
+
+
+
+#include <curlhttpt.h>
+
+#include <fcntl.h>
+
+#include <curl/curl.h>
+#include <curl/types.h>
+#include <curl/easy.h>
+
+#include <swlog.h>
+
+SWORD_NAMESPACE_START
+
+
+struct FtpFile {
+ const char *filename;
+ FILE *stream;
+ SWBuf *destBuf;
+};
+
+
+int my_httpfwrite(void *buffer, size_t size, size_t nmemb, void *stream);
+int my_httpfprogress(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow);
+
+static CURLHTTPTransport_init _CURLHTTPTransport_init;
+
+CURLHTTPTransport_init::CURLHTTPTransport_init() {
+ //curl_global_init(CURL_GLOBAL_DEFAULT); // curl_easy_init automatically calls it if needed
+}
+
+CURLHTTPTransport_init::~CURLHTTPTransport_init() {
+// CURLFTPT d-tor cleans this up
+// curl_global_cleanup();
+}
+
+int my_httpfwrite(void *buffer, size_t size, size_t nmemb, void *stream) {
+ struct FtpFile *out=(struct FtpFile *)stream;
+ if (out && !out->stream && !out->destBuf) {
+ /* open file for writing */
+ out->stream=fopen(out->filename, "wb");
+ if (!out->stream)
+ return -1; /* failure, can't open file to write */
+ }
+ if (out->destBuf) {
+ int s = out->destBuf->size();
+ out->destBuf->size(s+(size*nmemb));
+ memcpy(out->destBuf->getRawData()+s, buffer, size*nmemb);
+ return nmemb;
+ }
+ return fwrite(buffer, size, nmemb, out->stream);
+}
+
+
+int my_httpfprogress(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow) {
+ if (clientp) {
+ ((StatusReporter *)clientp)->statusUpdate(dltotal, dlnow);
+ }
+ return 0;
+}
+
+
+static int myhttp_trace(CURL *handle, curl_infotype type, unsigned char *data, size_t size, void *userp) {
+ SWBuf header;
+ (void)userp; /* prevent compiler warning */
+ (void)handle; /* prevent compiler warning */
+
+ switch (type) {
+ case CURLINFO_TEXT: header = "TEXT"; break;
+ case CURLINFO_HEADER_OUT: header = "=> Send header"; break;
+ case CURLINFO_HEADER_IN: header = "<= Recv header"; break;
+
+ // these we don't want to log (HUGE)
+ case CURLINFO_DATA_OUT: header = "=> Send data";
+ case CURLINFO_SSL_DATA_OUT: header = "=> Send SSL data";
+ case CURLINFO_DATA_IN: header = "<= Recv data";
+ case CURLINFO_SSL_DATA_IN: header = "<= Recv SSL data";
+ default: /* in case a new one is introduced to shock us */
+ return 0;
+ }
+
+ if (size > 120) size = 120;
+ SWBuf text;
+ text.size(size);
+ memcpy(text.getRawData(), data, size);
+ SWLog::getSystemLog()->logDebug("CURLHTTPTransport: %s: %s", header.c_str(), text.c_str());
+ return 0;
+}
+
+CURLHTTPTransport::CURLHTTPTransport(const char *host, StatusReporter *sr) : FTPTransport(host, sr) {
+ session = (CURL *)curl_easy_init();
+}
+
+
+CURLHTTPTransport::~CURLHTTPTransport() {
+ curl_easy_cleanup(session);
+}
+
+
+char CURLHTTPTransport::getURL(const char *destPath, const char *sourceURL, SWBuf *destBuf) {
+ signed char retVal = 0;
+ struct FtpFile ftpfile = {destPath, 0, destBuf};
+
+ CURLcode res;
+
+ if (session) {
+ curl_easy_setopt(session, CURLOPT_URL, sourceURL);
+
+ SWBuf credentials = u + ":" + p;
+ curl_easy_setopt(session, CURLOPT_USERPWD, credentials.c_str());
+ curl_easy_setopt(session, CURLOPT_WRITEFUNCTION, my_httpfwrite);
+ if (!passive)
+ curl_easy_setopt(session, CURLOPT_FTPPORT, "-");
+ curl_easy_setopt(session, CURLOPT_NOPROGRESS, 0);
+ curl_easy_setopt(session, CURLOPT_PROGRESSDATA, statusReporter);
+ curl_easy_setopt(session, CURLOPT_PROGRESSFUNCTION, my_httpfprogress);
+ curl_easy_setopt(session, CURLOPT_DEBUGFUNCTION, myhttp_trace);
+ /* Set a pointer to our struct to pass to the callback */
+ curl_easy_setopt(session, CURLOPT_FILE, &ftpfile);
+
+ /* Switch on full protocol/debug output */
+ curl_easy_setopt(session, CURLOPT_VERBOSE, true);
+
+ /* FTP connection settings */
+
+#if (LIBCURL_VERSION_MAJOR > 7) || \
+ ((LIBCURL_VERSION_MAJOR == 7) && (LIBCURL_VERSION_MINOR > 10)) || \
+ ((LIBCURL_VERSION_MAJOR == 7) && (LIBCURL_VERSION_MINOR == 10) && (LIBCURL_VERSION_PATCH >= 5))
+# define EPRT_AVAILABLE 1
+#endif
+
+#ifdef EPRT_AVAILABLE
+ curl_easy_setopt(session, CURLOPT_FTP_USE_EPRT, 0);
+ SWLog::getSystemLog()->logDebug("***** using CURLOPT_FTP_USE_EPRT\n");
+#endif
+
+
+ SWLog::getSystemLog()->logDebug("***** About to perform curl easy action. \n");
+ SWLog::getSystemLog()->logDebug("***** destPath: %s \n", destPath);
+ SWLog::getSystemLog()->logDebug("***** sourceURL: %s \n", sourceURL);
+ res = curl_easy_perform(session);
+ SWLog::getSystemLog()->logDebug("***** Finished performing curl easy action. \n");
+
+ if(CURLE_OK != res) {
+ retVal = -1;
+ }
+ }
+
+ if (ftpfile.stream)
+ fclose(ftpfile.stream); /* close the local file */
+
+ return retVal;
+}
+
+
+SWORD_NAMESPACE_END
+
diff --git a/src/mgr/encfiltmgr.cpp b/src/mgr/encfiltmgr.cpp
index 970900c..cb6dab4 100644
--- a/src/mgr/encfiltmgr.cpp
+++ b/src/mgr/encfiltmgr.cpp
@@ -22,7 +22,6 @@
#include <encfiltmgr.h>
#include <utilstr.h>
-#include <scsuutf8.h>
#include <latin1utf8.h>
#include <unicodertf.h>
@@ -45,7 +44,6 @@ SWORD_NAMESPACE_START
EncodingFilterMgr::EncodingFilterMgr (char enc)
: SWFilterMgr() {
- scsuutf8 = new SCSUUTF8();
latin1utf8 = new Latin1UTF8();
encoding = enc;
@@ -72,8 +70,6 @@ EncodingFilterMgr::EncodingFilterMgr (char enc)
* EncodingFilterMgr Destructor - Cleans up instance of EncodingFilterMgr
*/
EncodingFilterMgr::~EncodingFilterMgr() {
- if (scsuutf8)
- delete scsuutf8;
if (latin1utf8)
delete latin1utf8;
if (targetenc)
@@ -88,9 +84,6 @@ void EncodingFilterMgr::AddRawFilters(SWModule *module, ConfigEntMap &section) {
if (!encoding.length() || !stricmp(encoding.c_str(), "Latin-1")) {
module->AddRawFilter(latin1utf8);
}
- else if (!stricmp(encoding.c_str(), "SCSU")) {
- module->AddRawFilter(scsuutf8);
- }
}
void EncodingFilterMgr::AddEncodingFilters(SWModule *module, ConfigEntMap &section) {
diff --git a/src/mgr/filemgr.cpp b/src/mgr/filemgr.cpp
index 4a91dfa..dd49913 100644
--- a/src/mgr/filemgr.cpp
+++ b/src/mgr/filemgr.cpp
@@ -2,7 +2,7 @@
* filemgr.cpp - implementation of class FileMgr used for pooling file
* handles
*
- * $Id: filemgr.cpp 2108 2007-10-13 20:35:02Z scribe $
+ * $Id: filemgr.cpp 2245 2009-02-10 23:22:28Z scribe $
*
* Copyright 1998 CrossWire Bible Society (http://www.crosswire.org)
* CrossWire Bible Society
@@ -481,7 +481,7 @@ char FileMgr::getLine(FileDesc *fDesc, SWBuf &line) {
line.append(chunk+start, size);
}
}
- return ((len>0) || line.length());
+ return ((len > 0) || line.length());
}
diff --git a/src/mgr/ftplibftpt.cpp b/src/mgr/ftplibftpt.cpp
index 4921dd5..108d93e 100644
--- a/src/mgr/ftplibftpt.cpp
+++ b/src/mgr/ftplibftpt.cpp
@@ -1,7 +1,24 @@
/*****************************************************************************
* FTPLibFTPTransport functions
*
+ *
+ *
+ * Copyright 2009 CrossWire Bible Society (http://www.crosswire.org)
+ * CrossWire Bible Society
+ * P. O. Box 2528
+ * Tempe, AZ 85280-2528
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
*/
+
#include <stdio.h>
#include <fcntl.h>
@@ -43,7 +60,7 @@ char FTPLibFTPTransport::assureLoggedIn() {
if (ftpConnection == 0) {
SWLog::getSystemLog()->logDebug("connecting to host %s\n", host.c_str());
if (FtpConnect(host, &ftpConnection))
- if (FtpLogin("anonymous", "installmgr@user.com", ftpConnection)) {
+ if (FtpLogin(u.c_str(), p.c_str(), ftpConnection)) {
retVal = 0;
}
else {
diff --git a/src/mgr/ftptrans.cpp b/src/mgr/ftptrans.cpp
index ab0a605..76e8679 100644
--- a/src/mgr/ftptrans.cpp
+++ b/src/mgr/ftptrans.cpp
@@ -1,7 +1,25 @@
/*****************************************************************************
* FTPTransport functions
*
+ *
+ *
+ * Copyright 2009 CrossWire Bible Society (http://www.crosswire.org)
+ * CrossWire Bible Society
+ * P. O. Box 2528
+ * Tempe, AZ 85280-2528
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
*/
+
+
#include <ftptrans.h>
@@ -11,6 +29,9 @@
#include <dirent.h>
#include <swlog.h>
+extern "C" {
+#include <ftpparse.h>
+}
using std::vector;
@@ -40,6 +61,8 @@ void StatusReporter::statusUpdate(double dtTotal, double dlNow) {
FTPTransport::FTPTransport(const char *host, StatusReporter *statusReporter) {
this->statusReporter = statusReporter;
this->host = host;
+ u = "ftp";
+ p = "installmgr@user.com";
term = false;
}
diff --git a/src/mgr/installmgr.cpp b/src/mgr/installmgr.cpp
index 6a1704f..c3fec1a 100644
--- a/src/mgr/installmgr.cpp
+++ b/src/mgr/installmgr.cpp
@@ -2,9 +2,26 @@
* InstallMgr functions to be made into something usefully exposed by
* master Glassey
*
+ *
+ *
+ * Copyright 2009 CrossWire Bible Society (http://www.crosswire.org)
+ * CrossWire Bible Society
+ * P. O. Box 2528
+ * Tempe, AZ 85280-2528
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
*/
+
#ifndef EXCLUDEZLIB
extern "C" {
#include <untgz.h>
@@ -28,10 +45,12 @@ extern "C" {
#ifdef CURLAVAILABLE
#include <curlftpt.h>
+#include <curlhttpt.h>
#else
#include <ftplibftpt.h>
#endif
+#include <iostream>
SWORD_NAMESPACE_START
namespace {
@@ -43,6 +62,8 @@ void removeTrailingSlash(SWBuf &buf) {
buf.size(len-1);
}
+const char *masterRepoList = "masterRepoList.conf";
+
};
@@ -66,13 +87,24 @@ FTPTransport *InstallMgr::createFTPTransport(const char *host, StatusReporter *s
#endif
}
+FTPTransport *InstallMgr::createHTTPTransport(const char *host, StatusReporter *statusReporter) {
+#ifdef CURLAVAILABLE
+ return new CURLHTTPTransport(host, statusReporter);
+#else
+ return 0;
+#endif
+}
-InstallMgr::InstallMgr(const char *privatePath, StatusReporter *sr) {
+InstallMgr::InstallMgr(const char *privatePath, StatusReporter *sr, SWBuf u, SWBuf p) {
+ userDisclaimerConfirmed = false;
statusReporter = sr;
+ this->u = u;
+ this->p = p;
this->privatePath = 0;
this->transport = 0;
+ installConf = 0;
stdstr(&(this->privatePath), privatePath);
if (this->privatePath) {
int len = strlen(this->privatePath);
@@ -80,39 +112,59 @@ InstallMgr::InstallMgr(const char *privatePath, StatusReporter *sr) {
|| (this->privatePath[len-1] == '\\'))
this->privatePath[len-1] = 0;
}
- SWBuf confPath = (SWBuf)privatePath + "/InstallMgr.conf";
+ confPath = (SWBuf)privatePath + "/InstallMgr.conf";
FileMgr::createParent(confPath.c_str());
- installConf = new SWConfig(confPath.c_str());
+ readInstallConf();
+}
- SectionMap::iterator sourcesSection;
- ConfigEntMap::iterator sourceBegin;
- ConfigEntMap::iterator sourceEnd;
+InstallMgr::~InstallMgr() {
+ delete [] privatePath;
+ delete installConf;
+ clearSources();
+}
+
+void InstallMgr::clearSources() {
+ for (InstallSourceMap::iterator it = sources.begin(); it != sources.end(); ++it) {
+ delete it->second;
+ }
sources.clear();
+}
+
+void InstallMgr::readInstallConf() {
+
+ if (installConf) delete installConf;
+
+ installConf = new SWConfig(confPath.c_str());
+
+ clearSources();
- setFTPPassive(stricmp((*installConf)["General"]["PassiveFTP"].c_str(), "false")!=0);
+ setFTPPassive(stricmp((*installConf)["General"]["PassiveFTP"].c_str(), "false") != 0);
- sourcesSection = installConf->Sections.find("Sources");
- if (sourcesSection != installConf->Sections.end()) {
- sourceBegin = sourcesSection->second.lower_bound("FTPSource");
- sourceEnd = sourcesSection->second.upper_bound("FTPSource");
+ SectionMap::iterator confSection = installConf->Sections.find("Sources");
+ ConfigEntMap::iterator sourceBegin;
+ ConfigEntMap::iterator sourceEnd;
+
+ if (confSection != installConf->Sections.end()) {
+ sourceBegin = confSection->second.lower_bound("FTPSource");
+ sourceEnd = confSection->second.upper_bound("FTPSource");
while (sourceBegin != sourceEnd) {
InstallSource *is = new InstallSource("FTP", sourceBegin->second.c_str());
sources[is->caption] = is;
- SWBuf parent = (SWBuf)privatePath + "/" + is->source + "/file";
+ SWBuf parent = (SWBuf)privatePath + "/" + is->uid + "/file";
FileMgr::createParent(parent.c_str());
- is->localShadow = (SWBuf)privatePath + "/" + is->source;
+ is->localShadow = (SWBuf)privatePath + "/" + is->uid;
sourceBegin++;
}
}
defaultMods.clear();
- sourcesSection = installConf->Sections.find("General");
- if (sourcesSection != installConf->Sections.end()) {
- sourceBegin = sourcesSection->second.lower_bound("DefaultMod");
- sourceEnd = sourcesSection->second.upper_bound("DefaultMod");
+ confSection = installConf->Sections.find("General");
+ if (confSection != installConf->Sections.end()) {
+ sourceBegin = confSection->second.lower_bound("DefaultMod");
+ sourceEnd = confSection->second.upper_bound("DefaultMod");
while (sourceBegin != sourceEnd) {
defaultMods.insert(sourceBegin->second.c_str());
@@ -122,18 +174,24 @@ InstallMgr::InstallMgr(const char *privatePath, StatusReporter *sr) {
}
-InstallMgr::~InstallMgr() {
- delete [] privatePath;
- delete installConf;
+void InstallMgr::saveInstallConf() {
+
+ installConf->Sections["Sources"].erase("FTPSource");
for (InstallSourceMap::iterator it = sources.begin(); it != sources.end(); ++it) {
- delete it->second;
+ if (it->second) {
+ installConf->Sections["Sources"].insert(ConfigEntMap::value_type("FTPSource", it->second->getConfEnt().c_str()));
+ }
}
+ (*installConf)["General"]["PassiveFTP"] = (isFTPPassive()) ? "true" : "false";
+
+ installConf->Save();
}
void InstallMgr::terminate() { if (transport) transport->terminate(); }
+
int InstallMgr::removeModule(SWMgr *manager, const char *moduleName) {
SectionMap::iterator module;
ConfigEntMap::iterator fileBegin;
@@ -148,7 +206,7 @@ int InstallMgr::removeModule(SWMgr *manager, const char *moduleName) {
// to be sure all files are closed
// this does not remove the .conf information from SWMgr
manager->deleteModule(modName);
-
+
fileBegin = module->second.lower_bound("File");
fileEnd = module->second.upper_bound("File");
@@ -201,11 +259,23 @@ int InstallMgr::removeModule(SWMgr *manager, const char *moduleName) {
int InstallMgr::ftpCopy(InstallSource *is, const char *src, const char *dest, bool dirTransfer, const char *suffix) {
+
+ // assert user disclaimer has been confirmed
+ if (!isUserDisclaimerConfirmed()) return -1;
+
int retVal = 0;
FTPTransport *trans = createFTPTransport(is->source, statusReporter);
transport = trans; // set classwide current transport for other thread terminate() call
+ if (is->u.length()) {
+ trans->setUser(is->u);
+ trans->setPasswd(is->p);
+ }
+ else {
+ trans->setUser(u);
+ trans->setPasswd(p);
+ }
trans->setPassive(passive);
-
+
SWBuf urlPrefix = (SWBuf)"ftp://" + is->source;
// let's be sure we can connect. This seems to be necessary but sucks
@@ -215,7 +285,7 @@ int InstallMgr::ftpCopy(InstallSource *is, const char *src, const char *dest, bo
// return -1;
// }
-
+
if (dirTransfer) {
SWBuf dir = (SWBuf)is->directory.c_str();
removeTrailingSlash(dir);
@@ -270,7 +340,7 @@ int InstallMgr::installModule(SWMgr *destMgr, const char *fromLocation, const ch
SWLog::getSystemLog()->logDebug("***** modName: %s \n", modName);
if (is)
- sourceDir = (SWBuf)privatePath + "/" + is->source;
+ sourceDir = (SWBuf)privatePath + "/" + is->uid;
else sourceDir = fromLocation;
removeTrailingSlash(sourceDir);
@@ -409,53 +479,16 @@ int InstallMgr::installModule(SWMgr *destMgr, const char *fromLocation, const ch
return 1;
}
+int InstallMgr::refreshRemoteSource(InstallSource *is) {
-// override this and provide an input mechanism to allow your users
-// to enter the decipher code for a module.
-// return true you added the cipher code to the config.
-// default to return 'aborted'
-bool InstallMgr::getCipherCode(const char *modName, SWConfig *config) {
- return false;
-
-/* a sample implementation, roughly taken from the windows installmgr
-
- SectionMap::iterator section;
- ConfigEntMap::iterator entry;
- SWBuf tmpBuf;
- section = config->Sections.find(modName);
- if (section != config->Sections.end()) {
- entry = section->second.find("CipherKey");
- if (entry != section->second.end()) {
- entry->second = GET_USER_INPUT();
- config->Save();
-
- // LET'S SHOW THE USER SOME SAMPLE TEXT FROM THE MODULE
- SWMgr *mgr = new SWMgr();
- SWModule *mod = mgr->Modules[modName];
- mod->setKey("Ipet 2:12");
- tmpBuf = mod->StripText();
- mod->setKey("gen 1:10");
- tmpBuf += "\n\n";
- tmpBuf += mod->StripText();
- SOME_DIALOG_CONTROL->SETTEXT(tmpBuf.c_str());
- delete mgr;
-
- // if USER CLICKS OK means we should return true
- return true;
- }
- }
- return false;
-*/
-
-}
-
+ // assert user disclaimer has been confirmed
+ if (!isUserDisclaimerConfirmed()) return -1;
-int InstallMgr::refreshRemoteSource(InstallSource *is) {
- SWBuf root = (SWBuf)privatePath + (SWBuf)"/" + is->source.c_str();
+ SWBuf root = (SWBuf)privatePath + (SWBuf)"/" + is->uid.c_str();
removeTrailingSlash(root);
SWBuf target = root + "/mods.d";
int errorCode = -1; //0 means successful
-
+
FileMgr::removeDir(target.c_str());
if (!FileMgr::existsDir(target))
@@ -463,17 +496,17 @@ int InstallMgr::refreshRemoteSource(InstallSource *is) {
#ifndef EXCLUDEZLIB
SWBuf archive = root + "/mods.d.tar.gz";
-
+
errorCode = ftpCopy(is, "mods.d.tar.gz", archive.c_str(), false);
if (!errorCode) { //sucessfully downloaded the tar,gz of module configs
FileDesc *fd = FileMgr::getSystemFileMgr()->open(archive.c_str(), FileMgr::RDONLY);
untargz(fd->getFd(), root.c_str());
FileMgr::getSystemFileMgr()->close(fd);
}
- else if (!term) //if the tar.gz download was canceled don't continue with another download
+ else
#endif
errorCode = ftpCopy(is, "mods.d", target.c_str(), true, ".conf"); //copy the whole directory
-
+
is->flush();
return errorCode;
}
@@ -536,19 +569,96 @@ map<SWModule *, int> InstallMgr::getModuleStatus(const SWMgr &base, const SWMgr
}
+/************************************************************************
+ * refreshRemoteSourceConfiguration - grab master list of know remote
+ * sources and integrate it with our configurations.
+ */
+int InstallMgr::refreshRemoteSourceConfiguration() {
+
+ // assert user disclaimer has been confirmed
+ if (!isUserDisclaimerConfirmed()) return -1;
+
+ SWBuf root = (SWBuf)privatePath;
+ removeTrailingSlash(root);
+ SWBuf masterRepoListPath = root + "/" + masterRepoList;
+ InstallSource is("FTP");
+ is.source = "ftp.crosswire.org";
+ is.directory = "/pub/sword";
+ int errorCode = ftpCopy(&is, masterRepoList, masterRepoListPath.c_str(), false);
+ if (!errorCode) { //sucessfully downloaded the repo list
+ SWConfig masterList(masterRepoListPath);
+ SectionMap::iterator sections = masterList.Sections.find("Repos");
+ if (sections != masterList.Sections.end()) {
+ for (ConfigEntMap::iterator actions = sections->second.begin(); actions != sections->second.end(); actions++) {
+ // Search through our current sources and see if we have a matching UID
+ InstallSourceMap::iterator it;
+ for (it = sources.begin(); it != sources.end(); ++it) {
+ // is this our UID?
+ if ((it->second) && (it->second->uid == actions->first)) {
+ if (actions->second == "REMOVE") {
+ // be sure to call save/reload after this
+ // or this could be dangerous
+ delete it->second;
+ it->second = 0;
+ }
+ else {
+ SWBuf key = actions->second.stripPrefix('=');
+ if (key == "FTPSource") {
+ // we might consider instantiating a temp IS
+ // from our config string and then copy only
+ // some entries. This would allow the use to
+ // change some fields and not have them overwritten
+ // but it seems like we might want to change any
+ // of the current fields so we don't do this now
+ // InstallSource i("FTP", actions->second);
+ delete it->second;
+ it->second = new InstallSource("FTP", actions->second.c_str());
+ it->second->uid = actions->first;
+ }
+ }
+ break;
+ }
+ }
+ // didn't find our UID, let's add it
+ if (it == sources.end()) {
+ SWBuf key = actions->second.stripPrefix('=');
+ if (key == "FTPSource") {
+ if (actions->second != "REMOVE") {
+ InstallSource *is = new InstallSource("FTP", actions->second.c_str());
+ is->uid = actions->first;
+ sources[is->caption] = is;
+ }
+ }
+ }
+ }
+
+ // persist and re-read
+ saveInstallConf();
+ readInstallConf();
+
+ return 0;
+ }
+ }
+ return -1;
+}
+
+
InstallSource::InstallSource(const char *type, const char *confEnt) {
this->type = type;
mgr = 0;
userData = 0;
if (confEnt) {
- char *buf = 0;
- stdstr(&buf, confEnt);
+ SWBuf buf = confEnt;
+ caption = buf.stripPrefix('|', true);
+ source = buf.stripPrefix('|', true);
+ directory = buf.stripPrefix('|', true);
+ u = buf.stripPrefix('|', true);
+ p = buf.stripPrefix('|', true);
+ uid = buf.stripPrefix('|', true);
+
+ if (!uid.length()) uid = source;
- caption = strtok(buf, "|");
- source = strtok(0, "|");
- directory = strtok(0, "|");
removeTrailingSlash(directory);
- delete [] buf;
}
}
diff --git a/src/mgr/localemgr.cpp b/src/mgr/localemgr.cpp
index ead076a..af57ca0 100644
--- a/src/mgr/localemgr.cpp
+++ b/src/mgr/localemgr.cpp
@@ -2,7 +2,7 @@
* localemgr.cpp - implementation of class LocaleMgr used to interact with
* registered locales for a sword installation
*
- * $Id: localemgr.cpp 2080 2007-09-17 06:21:29Z scribe $
+ * $Id: localemgr.cpp 2321 2009-04-13 01:17:00Z scribe $
*
* Copyright 1998 CrossWire Bible Society (http://www.crosswire.org)
* CrossWire Bible Society
@@ -49,8 +49,9 @@ public:
LocaleMgr *LocaleMgr::getSystemLocaleMgr() {
- if (!systemLocaleMgr)
- systemLocaleMgr = new LocaleMgr();
+ if (!systemLocaleMgr) {
+ setSystemLocaleMgr(new LocaleMgr());
+ }
return systemLocaleMgr;
}
@@ -60,6 +61,8 @@ void LocaleMgr::setSystemLocaleMgr(LocaleMgr *newLocaleMgr) {
if (systemLocaleMgr)
delete systemLocaleMgr;
systemLocaleMgr = newLocaleMgr;
+ SWLocale *locale = new SWLocale(0);
+ systemLocaleMgr->locales->insert(LocaleMap::value_type(locale->getName(), locale));
}
@@ -67,18 +70,29 @@ LocaleMgr::LocaleMgr(const char *iConfigPath) {
locales = new LocaleMap();
char *prefixPath = 0;
char *configPath = 0;
+ SWConfig *sysConf = 0;
char configType = 0;
SWBuf path;
std::list<SWBuf> augPaths;
+ ConfigEntMap::iterator entry;
defaultLocaleName = 0;
if (!iConfigPath) {
SWLog::getSystemLog()->logDebug("LOOKING UP LOCALE DIRECTORY...");
- SWMgr::findConfig(&configType, &prefixPath, &configPath, &augPaths);
+ SWMgr::findConfig(&configType, &prefixPath, &configPath, &augPaths, &sysConf);
+ if (sysConf) {
+ if ((entry = sysConf->Sections["Install"].find("LocalePath")) != sysConf->Sections["Install"].end()) {
+ configType = 9; // our own
+ stdstr(&prefixPath, (char *)entry->second.c_str());
+ SWLog::getSystemLog()->logDebug("LocalePath provided in sysConfig.");
+ }
+ }
SWLog::getSystemLog()->logDebug("LOOKING UP LOCALE DIRECTORY COMPLETE.");
}
- else configPath = (char *)iConfigPath;
+ else {
+ loadConfigDir(iConfigPath);
+ }
if (prefixPath) {
switch (configType) {
@@ -102,7 +116,7 @@ LocaleMgr::LocaleMgr(const char *iConfigPath) {
}
}
- if (augPaths.size()) { //load locale files from all augmented paths
+ if (augPaths.size() && configType != 9) { //load locale files from all augmented paths
std::list<SWBuf>::iterator it = augPaths.begin();
std::list<SWBuf>::iterator end = augPaths.end();
@@ -117,13 +131,16 @@ LocaleMgr::LocaleMgr(const char *iConfigPath) {
// Locales will be invalidated if you change the StringMgr
// So only use the default hardcoded locale and let the
// frontends change the locale if they want
- stdstr(&defaultLocaleName, "en_US");
+ stdstr(&defaultLocaleName, SWLocale::DEFAULT_LOCALE_NAME);
if (prefixPath)
delete [] prefixPath;
if (configPath)
delete [] configPath;
+
+ if (sysConf)
+ delete sysConf;
}
@@ -200,7 +217,7 @@ SWLocale *LocaleMgr::getLocale(const char *name) {
return (*it).second;
SWLog::getSystemLog()->logWarning("LocaleMgr::getLocale failed to find %s\n", name);
- return 0;
+ return (*locales)[SWLocale::DEFAULT_LOCALE_NAME];
}
diff --git a/src/mgr/swconfig.cpp b/src/mgr/swconfig.cpp
index 376c206..309f686 100644
--- a/src/mgr/swconfig.cpp
+++ b/src/mgr/swconfig.cpp
@@ -2,7 +2,7 @@
* swconfig.cpp - implementation of Class SWConfig used for saving and
* retrieval of configuration information
*
- * $Id: swconfig.cpp 1828 2005-06-10 16:24:46Z scribe $
+ * $Id: swconfig.cpp 2218 2008-12-23 09:33:38Z scribe $
*
* Copyright 1998 CrossWire Bible Society (http://www.crosswire.org)
* CrossWire Bible Society
@@ -28,6 +28,9 @@
SWORD_NAMESPACE_START
+SWConfig::SWConfig() {
+}
+
SWConfig::SWConfig(const char * ifilename) {
filename = ifilename;
Load();
@@ -38,6 +41,9 @@ SWConfig::~SWConfig() {
}
void SWConfig::Load() {
+
+ if (!filename.size()) return; // assert we have a filename
+
FileDesc *cfile;
char *buf, *data;
SWBuf line;
@@ -60,27 +66,30 @@ void SWConfig::Load() {
}
while (goodLine) {
- buf = new char [ line.length() + 1 ];
- strcpy(buf, line.c_str());
- if (*strstrip(buf) == '[') {
- if (!first)
- Sections.insert(SectionMap::value_type(sectname, cursect));
- else first = false;
-
- cursect.erase(cursect.begin(), cursect.end());
-
- strtok(buf, "]");
- sectname = buf+1;
- }
- else {
- strtok(buf, "=");
- if ((*buf) && (*buf != '=')) {
- if ((data = strtok(NULL, "")))
- cursect.insert(ConfigEntMap::value_type(buf, strstrip(data)));
- else cursect.insert(ConfigEntMap::value_type(buf, ""));
+ // ignore commented lines
+ if (!line.startsWith("#")) {
+ buf = new char [ line.length() + 1 ];
+ strcpy(buf, line.c_str());
+ if (*strstrip(buf) == '[') {
+ if (!first)
+ Sections.insert(SectionMap::value_type(sectname, cursect));
+ else first = false;
+
+ cursect.erase(cursect.begin(), cursect.end());
+
+ strtok(buf, "]");
+ sectname = buf+1;
}
+ else {
+ strtok(buf, "=");
+ if ((*buf) && (*buf != '=')) {
+ if ((data = strtok(NULL, "")))
+ cursect.insert(ConfigEntMap::value_type(buf, strstrip(data)));
+ else cursect.insert(ConfigEntMap::value_type(buf, ""));
+ }
+ }
+ delete [] buf;
}
- delete [] buf;
goodLine = FileMgr::getLine(cfile, line);
}
if (!first)
@@ -92,6 +101,9 @@ void SWConfig::Load() {
void SWConfig::Save() {
+
+ if (!filename.size()) return; // assert we have a filename
+
FileDesc *cfile;
SWBuf buf;
SectionMap::iterator sit;
diff --git a/src/mgr/swlocale.cpp b/src/mgr/swlocale.cpp
index facb1ee..3d09313 100644
--- a/src/mgr/swlocale.cpp
+++ b/src/mgr/swlocale.cpp
@@ -2,7 +2,7 @@
* swlocale.cpp - implementation of Class SWLocale used for retrieval
* of locale lookups
*
- * $Id: swlocale.cpp 1864 2005-11-20 06:06:40Z scribe $
+ * $Id: swlocale.cpp 2346 2009-04-27 01:53:58Z scribe $
*
* Copyright 2000 CrossWire Bible Society (http://www.crosswire.org)
* CrossWire Bible Society
@@ -25,29 +25,42 @@
#include <map>
#include <swconfig.h>
#include <versekey.h>
+#include <versemgr.h>
SWORD_NAMESPACE_START
typedef std::map < SWBuf, SWBuf, std::less < SWBuf > >LookupMap;
+const char *SWLocale::DEFAULT_LOCALE_NAME="en_US";
+
// I have bridge patterns, but this hides swconfig and map from lots o stuff
class SWLocale::Private {
public:
LookupMap lookupTable;
+ LookupMap mergedAbbrevs;
};
-SWLocale::SWLocale(const char * ifilename) {
+SWLocale::SWLocale(const char *ifilename) {
p = new Private;
ConfigEntMap::iterator confEntry;
- name = 0;
- description = 0;
- encoding = 0;
- bookAbbrevs = 0;
- BMAX = 0;
- books = 0;
- localeSource = new SWConfig(ifilename);
+ name = 0;
+ description = 0;
+ encoding = 0;
+ bookAbbrevs = 0;
+ bookLongNames = 0;
+ bookPrefAbbrev = 0;
+ if (ifilename) {
+ localeSource = new SWConfig(ifilename);
+ }
+ else {
+ localeSource = new SWConfig(0);
+ (*localeSource)["Meta"]["Name"] = DEFAULT_LOCALE_NAME;
+ (*localeSource)["Meta"]["Description"] = "English (US)";
+ bookAbbrevs = (struct abbrev *)builtin_abbrevs;
+ for (abbrevsCnt = 0; builtin_abbrevs[abbrevsCnt].osis[0]; abbrevsCnt++);
+ }
confEntry = localeSource->Sections["Meta"].find("Name");
if (confEntry != localeSource->Sections["Meta"].end())
@@ -76,15 +89,9 @@ SWLocale::~SWLocale() {
if (name)
delete [] name;
- if (bookAbbrevs)
+ if (bookAbbrevs != builtin_abbrevs)
delete [] bookAbbrevs;
- if (BMAX) {
- for (int i = 0; i < 2; i++)
- delete [] books[i];
- delete [] BMAX;
- delete [] books;
- }
delete p;
}
@@ -145,60 +152,35 @@ void SWLocale::augment(SWLocale &addFrom) {
*localeSource += *addFrom.localeSource;
}
-//#define NONNUMERICLOCALETHING 1
-const struct abbrev *SWLocale::getBookAbbrevs() {
+const struct abbrev *SWLocale::getBookAbbrevs(int *retSize) {
static const char *nullstr = "";
if (!bookAbbrevs) {
- ConfigEntMap::iterator it;
- int i, j;
- int size = localeSource->Sections["Book Abbrevs"].size();
+ // Assure all english abbrevs are present
+ for (int j = 0; builtin_abbrevs[j].osis[0]; j++) {
+ p->mergedAbbrevs[builtin_abbrevs[j].ab] = builtin_abbrevs[j].osis;
+ }
+ ConfigEntMap::iterator it = localeSource->Sections["Book Abbrevs"].begin();
+ ConfigEntMap::iterator end = localeSource->Sections["Book Abbrevs"].end();
+ for (; it != end; it++) {
+ p->mergedAbbrevs[it->first.c_str()] = it->second.c_str();
+ }
+ int size = p->mergedAbbrevs.size();
bookAbbrevs = new struct abbrev[size + 1];
- for (i = 0, j = 0, it = localeSource->Sections["Book Abbrevs"].begin(); it != localeSource->Sections["Book Abbrevs"].end(); it++, i++) {
- #ifdef NONNUMERICLOCALETHING
- int booknum = VerseKey::getOSISBookNum((*it).second.c_str());
- if (booknum != -1) {
- bookAbbrevs[j].ab = (*it).first.c_str();
- bookAbbrevs[j].book = booknum;
- j++;
- }
- #else
- bookAbbrevs[i].ab = (*it).first.c_str();
- bookAbbrevs[i].book = atoi((*it).second.c_str());
- j++;
- #endif
- //printf("SWLocale::getBookAbbrevs %s:%s %d\n",bookAbbrevs[i].ab,
- // (*it).second.c_str(), bookAbbrevs[i].book);
+ int i = 0;
+ for (LookupMap::iterator it = p->mergedAbbrevs.begin(); it != p->mergedAbbrevs.end(); it++, i++) {
+ bookAbbrevs[i].ab = it->first.c_str();
+ bookAbbrevs[i].osis = it->second.c_str();
}
- bookAbbrevs[j].ab = nullstr;
- bookAbbrevs[j].book = -1;
+
+ bookAbbrevs[i].ab = nullstr;
+ bookAbbrevs[i].osis = nullstr;
+ abbrevsCnt = size;
}
+ *retSize = abbrevsCnt;
return bookAbbrevs;
}
-void SWLocale::getBooks(char **iBMAX, struct sbook ***ibooks) {
- if (!BMAX) {
- BMAX = new char [2];
- BMAX[0] = VerseKey::builtin_BMAX[0];
- BMAX[1] = VerseKey::builtin_BMAX[1];
-
- books = new struct sbook *[2];
- books[0] = new struct sbook[BMAX[0]];
- books[1] = new struct sbook[BMAX[1]];
-
- for (int i = 0; i < 2; i++) {
- for (int j = 0; j < BMAX[i]; j++) {
- books[i][j] = VerseKey::builtin_books[i][j];
- books[i][j].name = translate(VerseKey::builtin_books[i][j].name);
- }
- }
- }
-
- *iBMAX = BMAX;
- *ibooks = books;
-}
-
-
SWORD_NAMESPACE_END
diff --git a/src/mgr/swmgr.cpp b/src/mgr/swmgr.cpp
index 86c04d7..3ee253f 100644
--- a/src/mgr/swmgr.cpp
+++ b/src/mgr/swmgr.cpp
@@ -2,7 +2,7 @@
* swmgr.cpp - implementaion of class SWMgr used to interact with an install
* base of sword modules.
*
- * $Id: swmgr.cpp 2169 2008-05-18 02:50:53Z scribe $
+ * $Id: swmgr.cpp 2374 2009-05-04 03:48:01Z scribe $
*
* Copyright 1998 CrossWire Bible Society (http://www.crosswire.org)
* CrossWire Bible Society
@@ -58,6 +58,7 @@
#include <osislemma.h>
#include <osisredletterwords.h>
#include <osismorphsegmentation.h>
+#include <osisruby.h>
#include <osisscripref.h>
#include <thmlstrongs.h>
#include <thmlfootnotes.h>
@@ -75,6 +76,7 @@
#include <utf8greekaccents.h>
#include <utf8cantillation.h>
#include <utf8hebrewpoints.h>
+#include <utf8arabicpoints.h>
#include <greeklexattribs.h>
#include <swfiltermgr.h>
#include <swcipher.h>
@@ -177,6 +179,10 @@ void SWMgr::init() {
optionFilters.insert(OptionFilterMap::value_type("OSISMorphSegmentation", tmpFilter));
cleanupFilters.push_back(tmpFilter);
+ tmpFilter = new OSISRuby();
+ optionFilters.insert(OptionFilterMap::value_type("OSISRuby", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
tmpFilter = new ThMLStrongs();
optionFilters.insert(OptionFilterMap::value_type("ThMLStrongs", tmpFilter));
cleanupFilters.push_back(tmpFilter);
@@ -209,6 +215,10 @@ void SWMgr::init() {
optionFilters.insert(OptionFilterMap::value_type("UTF8HebrewPoints", tmpFilter));
cleanupFilters.push_back(tmpFilter);
+ tmpFilter = new UTF8ArabicPoints();
+ optionFilters.insert(OptionFilterMap::value_type("UTF8ArabicPoints", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
tmpFilter = new UTF8Cantillation();
optionFilters.insert(OptionFilterMap::value_type("UTF8Cantillation", tmpFilter));
cleanupFilters.push_back(tmpFilter);
@@ -240,7 +250,24 @@ void SWMgr::init() {
teiplain = new TEIPlain();
cleanupFilters.push_back(teiplain);
-//#endif
+}
+
+
+SWBuf SWMgr::getHomeDir() {
+
+ // figure out 'home' directory for app data
+ SWBuf homeDir = getenv("HOME");
+ if (!homeDir.length()) {
+ // silly windows
+ homeDir = getenv("APPDATA");
+ }
+ if (homeDir.length()) {
+ if ((homeDir[homeDir.length()-1] != '\\') && (homeDir[homeDir.length()-1] != '/')) {
+ homeDir += "/";
+ }
+ }
+
+ return homeDir;
}
@@ -259,10 +286,10 @@ void SWMgr::commonInit(SWConfig *iconfig, SWConfig *isysconfig, bool autoload, S
}
else config = 0;
if (isysconfig) {
- sysconfig = isysconfig;
+ sysConfig = isysconfig;
mysysconfig = 0;
}
- else sysconfig = 0;
+ else sysConfig = 0;
if (autoload)
Load();
@@ -311,7 +338,7 @@ SWMgr::SWMgr(const char *iConfigPath, bool autoload, SWFilterMgr *filterMgr, boo
}
config = 0;
- sysconfig = 0;
+ sysConfig = 0;
if (autoload && configPath)
Load();
@@ -345,32 +372,46 @@ SWMgr::~SWMgr() {
}
-void SWMgr::findConfig(char *configType, char **prefixPath, char **configPath, std::list<SWBuf> *augPaths, SWConfig *providedSysConf) {
+void SWMgr::findConfig(char *configType, char **prefixPath, char **configPath, std::list<SWBuf> *augPaths, SWConfig **providedSysConf) {
SWBuf path;
SWBuf sysConfPath;
ConfigEntMap::iterator entry;
ConfigEntMap::iterator lastEntry;
- char *envsworddir = getenv("SWORD_PATH");
- char *envhomedir = getenv("HOME");
SWConfig *sysConf = 0;
+ SWBuf sysConfDataPath = "";
*configType = 0;
+ SWBuf homeDir = getHomeDir();
+
// check for a sysConf passed in to us
SWLog::getSystemLog()->logDebug("Checking for provided SWConfig(\"sword.conf\")...");
- if (providedSysConf) {
- sysConf = providedSysConf;
+ if (providedSysConf && *providedSysConf) {
+ sysConf = *providedSysConf;
SWLog::getSystemLog()->logDebug("found.");
}
- else {
+
+ // if we haven't been given our datapath in a sysconf, we need to track it down
+ if (!sysConf) {
// check working directory
SWLog::getSystemLog()->logDebug("Checking working directory for sword.conf...");
if (FileMgr::existsFile(".", "sword.conf")) {
SWLog::getSystemLog()->logDebug("Overriding any systemwide or ~/.sword/ sword.conf with one found in current directory.");
sysConfPath = "./sword.conf";
+ sysConf = new SWConfig(sysConfPath);
+ if ((entry = sysConf->Sections["Install"].find("DataPath")) != sysConf->Sections["Install"].end()) {
+ sysConfDataPath = (*entry).second;
+ }
+ if (providedSysConf) {
+ *providedSysConf = sysConf;
+ }
+ else {
+ delete sysConf;
+ sysConf = 0;
+ }
}
- else {
+ if (!sysConfDataPath.size()) {
SWLog::getSystemLog()->logDebug("Checking working directory for mods.conf...");
if (FileMgr::existsFile(".", "mods.conf")) {
SWLog::getSystemLog()->logDebug("found.");
@@ -388,7 +429,7 @@ void SWMgr::findConfig(char *configType, char **prefixPath, char **configPath, s
return;
}
- // check working directory ../library/
+ // check working directory ../library/
SWLog::getSystemLog()->logDebug("Checking working directory ../library/ for mods.d...");
if (FileMgr::existsDir("../library", "mods.d")) {
SWLog::getSystemLog()->logDebug("found.");
@@ -399,13 +440,14 @@ void SWMgr::findConfig(char *configType, char **prefixPath, char **configPath, s
}
// check environment variable SWORD_PATH
- SWLog::getSystemLog()->logDebug("Checking SWORD_PATH...");
+ SWLog::getSystemLog()->logDebug("Checking $SWORD_PATH...");
- if (envsworddir != NULL) {
+ SWBuf envsworddir = getenv("SWORD_PATH");
+ if (envsworddir.length()) {
- SWLog::getSystemLog()->logDebug("found (%s).", envsworddir);
+ SWLog::getSystemLog()->logDebug("found (%s).", envsworddir.c_str());
path = envsworddir;
- if ((envsworddir[strlen(envsworddir)-1] != '\\') && (envsworddir[strlen(envsworddir)-1] != '/'))
+ if ((envsworddir[envsworddir.length()-1] != '\\') && (envsworddir[envsworddir.length()-1] != '/'))
path += "/";
SWLog::getSystemLog()->logDebug("Checking $SWORD_PATH for mods.conf...");
@@ -446,29 +488,38 @@ void SWMgr::findConfig(char *configType, char **prefixPath, char **configPath, s
sysConfPath = gfp;
delete [] globPaths;
- SWBuf homeDir = envhomedir;
- if (homeDir.size() > 0) {
- if ((homeDir[homeDir.size()-1] != '\\') && (homeDir[homeDir.size()-1] != '/'))
- homeDir += "/";
- homeDir += ".sword/sword.conf";
- if (FileMgr::existsFile(homeDir)) {
- SWLog::getSystemLog()->logDebug("Overriding any systemwide sword.conf with one found in users home directory.");
- sysConfPath = homeDir;
+ if (homeDir.length()) {
+ SWBuf tryPath = homeDir;
+ tryPath += ".sword/sword.conf";
+ if (FileMgr::existsFile(tryPath)) {
+ SWLog::getSystemLog()->logDebug("Overriding any systemwide sword.conf with one found in users home directory (%s)", tryPath.c_str());
+ sysConfPath = tryPath;
+ }
+ else {
+ SWBuf tryPath = homeDir;
+ tryPath += "sword/sword.conf";
+ if (FileMgr::existsFile(tryPath)) {
+ SWLog::getSystemLog()->logDebug("Overriding any systemwide sword.conf with one found in users home directory (%s)", tryPath.c_str());
+ sysConfPath = tryPath;
+ }
}
}
}
}
- if (sysConfPath.size()) {
+ if (!sysConf && sysConfPath.size()) {
sysConf = new SWConfig(sysConfPath);
}
if (sysConf) {
if ((entry = sysConf->Sections["Install"].find("DataPath")) != sysConf->Sections["Install"].end()) {
- path = (*entry).second;
- if (((*entry).second.c_str()[strlen((*entry).second.c_str())-1] != '\\') && ((*entry).second.c_str()[strlen((*entry).second.c_str())-1] != '/'))
- path += "/";
+ sysConfDataPath = (*entry).second;
+ }
+ if (sysConfDataPath.size()) {
+ if ((!sysConfDataPath.endsWith("\\")) && (!sysConfDataPath.endsWith("/")))
+ sysConfDataPath += "/";
+ path = sysConfDataPath;
SWLog::getSystemLog()->logDebug("DataPath in %s is set to %s.", sysConfPath.c_str(), path.c_str());
SWLog::getSystemLog()->logDebug("Checking for mods.conf in DataPath...");
@@ -490,6 +541,10 @@ void SWMgr::findConfig(char *configType, char **prefixPath, char **configPath, s
*configType = 1;
}
}
+ }
+
+ // do some extra processing of sysConf if we have one
+ if (sysConf) {
if (augPaths) {
augPaths->clear();
entry = sysConf->Sections["Install"].lower_bound("AugmentPath");
@@ -501,23 +556,72 @@ void SWMgr::findConfig(char *configType, char **prefixPath, char **configPath, s
augPaths->push_back(path);
}
}
- }
-
- if ((sysConf) && (!providedSysConf)) {
- delete sysConf;
+ if (providedSysConf) {
+ *providedSysConf = sysConf;
+ }
+ else delete sysConf;
}
if (*configType)
return;
+ // WE STILL HAVEN'T FOUND A CONFIGURATION. LET'S LOOK IN SOME OS SPECIFIC
+ // LOCATIONS
+ //
+ // for various flavors of windoze...
+ // check %ALLUSERSPROFILE%/Application Data/sword/
+
+ SWLog::getSystemLog()->logDebug("Checking $ALLUSERSPROFILE/Application Data/sword/...");
+
+ SWBuf envallusersdir = getenv("ALLUSERSPROFILE");
+ if (envallusersdir.length()) {
+ SWLog::getSystemLog()->logDebug("found (%s).", envallusersdir.c_str());
+ path = envallusersdir;
+ if ((!path.endsWith("\\")) && (!path.endsWith("/")))
+ path += "/";
+
+ path += "Application Data/sword/";
+ SWLog::getSystemLog()->logDebug("Checking %s for mods.d...", path.c_str());
+ if (FileMgr::existsDir(path.c_str(), "mods.d")) {
+ SWLog::getSystemLog()->logDebug("found.");
+ stdstr(prefixPath, path.c_str());
+ path += "mods.d";
+ stdstr(configPath, path.c_str());
+ *configType = 1;
+ return;
+ }
+ }
+
+ // for Mac OSX...
+ // check $HOME/Library/Application Support/Sword/
+
+ SWLog::getSystemLog()->logDebug("Checking $HOME/Library/Application Support/Sword/...");
+
+ SWBuf pathCheck = getHomeDir();
+ if (pathCheck.length()) {
+ SWLog::getSystemLog()->logDebug("found (%s).", pathCheck.c_str());
+ path = pathCheck;
+ if ((!path.endsWith("\\")) && (!path.endsWith("/")))
+ path += "/";
+
+ SWLog::getSystemLog()->logDebug("Checking %s for mods.d...", path.c_str());
+ if (FileMgr::existsDir(path.c_str(), "mods.d")) {
+ SWLog::getSystemLog()->logDebug("found.");
+ stdstr(prefixPath, path.c_str());
+ path += "mods.d";
+ stdstr(configPath, path.c_str());
+ *configType = 1;
+ return;
+ }
+ }
+
+ // FINALLY CHECK PERSONAL HOME DIRECTORY LOCATIONS
// check ~/.sword/
SWLog::getSystemLog()->logDebug("Checking home directory for ~/.sword...");
- if (envhomedir != NULL) {
- path = envhomedir;
- if ((envhomedir[strlen(envhomedir)-1] != '\\') && (envhomedir[strlen(envhomedir)-1] != '/'))
- path += "/";
+ if (homeDir.length()) {
+ path = homeDir;
path += ".sword/";
SWLog::getSystemLog()->logDebug(" Checking for %smods.conf...", path.c_str());
if (FileMgr::existsFile(path.c_str(), "mods.conf")) {
@@ -537,6 +641,18 @@ void SWMgr::findConfig(char *configType, char **prefixPath, char **configPath, s
*configType = 2;
return;
}
+
+ path = homeDir;
+ path += "sword/";
+ SWLog::getSystemLog()->logDebug(" Checking for %smods.d...", path.c_str());
+ if (FileMgr::existsDir(path.c_str(), "mods.d")) {
+ SWLog::getSystemLog()->logDebug("found.");
+ stdstr(prefixPath, path.c_str());
+ path += "mods.d";
+ stdstr(configPath, path.c_str());
+ *configType = 2;
+ return;
+ }
}
}
@@ -551,21 +667,19 @@ void SWMgr::loadConfigDir(const char *ipath)
rewinddir(dir);
while ((ent = readdir(dir))) {
//check whether it ends with .conf, if it doesn't skip it!
- if (ent->d_name && (strlen(ent->d_name) > 5) && strncmp(".conf", (ent->d_name + strlen(ent->d_name) - 5), 5 )) {
+ if (!ent->d_name || (strlen(ent->d_name) <= 5) || strncmp(".conf", (ent->d_name + strlen(ent->d_name) - 5), 5 )) {
continue;
}
- if ((strcmp(ent->d_name, ".")) && (strcmp(ent->d_name, ".."))) {
- newmodfile = ipath;
- if ((ipath[strlen(ipath)-1] != '\\') && (ipath[strlen(ipath)-1] != '/'))
- newmodfile += "/";
- newmodfile += ent->d_name;
- if (config) {
- SWConfig tmpConfig(newmodfile.c_str());
- *config += tmpConfig;
- }
- else config = myconfig = new SWConfig(newmodfile.c_str());
+ newmodfile = ipath;
+ if ((ipath[strlen(ipath)-1] != '\\') && (ipath[strlen(ipath)-1] != '/'))
+ newmodfile += "/";
+ newmodfile += ent->d_name;
+ if (config) {
+ SWConfig tmpConfig(newmodfile.c_str());
+ *config += tmpConfig;
}
+ else config = myconfig = new SWConfig(newmodfile.c_str());
}
closedir(dir);
@@ -646,7 +760,9 @@ signed char SWMgr::Load() {
if (!config) { // If we weren't passed a config object at construction, find a config file
if (!configPath) { // If we weren't passed a config path at construction...
SWLog::getSystemLog()->logDebug("LOOKING UP MODULE CONFIGURATION...");
- findConfig(&configType, &prefixPath, &configPath, &augPaths, sysconfig);
+ SWConfig *externalSysConf = sysConfig; // if we have a sysConf before findConfig, then we were provided one from an external source.
+ findConfig(&configType, &prefixPath, &configPath, &augPaths, &sysConfig);
+ if (!externalSysConf) mysysconfig = sysConfig; // remind us to delete our own sysConfig in d-tor
SWLog::getSystemLog()->logDebug("LOOKING UP MODULE CONFIGURATION COMPLETE.");
}
if (configPath) {
@@ -680,17 +796,18 @@ signed char SWMgr::Load() {
}
if (augmentHome) {
// augment config with ~/.sword/mods.d if it exists ---------------------
- char *envhomedir = getenv("HOME");
- if (envhomedir != NULL && configType != 2) { // 2 = user only
- SWBuf path = envhomedir;
- if ((envhomedir[strlen(envhomedir)-1] != '\\') && (envhomedir[strlen(envhomedir)-1] != '/'))
- path += "/";
+ SWBuf homeDir = getHomeDir();
+ if (homeDir.length() && configType != 2) { // 2 = user only
+ SWBuf path = homeDir;
path += ".sword/";
augmentModules(path.c_str(), mgrModeMultiMod);
+ path = homeDir;
+ path += "sword/";
+ augmentModules(path.c_str(), mgrModeMultiMod);
}
}
// -------------------------------------------------------------------------
- if ( !Modules.size() ) // config exists, but no modules
+ if (!Modules.size()) // config exists, but no modules
ret = 1;
}
@@ -718,6 +835,8 @@ SWModule *SWMgr::CreateMod(const char *name, const char *driver, ConfigEntMap &s
if ((prefixPath[strlen(prefixPath)-1] != '\\') && (prefixPath[strlen(prefixPath)-1] != '/'))
datapath += "/";
+ SWBuf versification = ((entry = section.find("Versification")) != section.end()) ? (*entry).second : (SWBuf)"KJV";
+
// DataPath - relative path to data used by module driver. May be a directory, may be a File.
// Typically not useful by outside world. See AbsoluteDataPath, PrefixPath, and RelativePrefixPath
// below.
@@ -749,9 +868,7 @@ SWModule *SWMgr::CreateMod(const char *name, const char *driver, ConfigEntMap &s
else
markup = FMT_GBF;
- if (!stricmp(encoding.c_str(), "SCSU"))
- enc = ENC_SCSU;
- else if (!stricmp(encoding.c_str(), "UTF-8")) {
+ if (!stricmp(encoding.c_str(), "UTF-8")) {
enc = ENC_UTF8;
}
else enc = ENC_LATIN1;
@@ -795,17 +912,17 @@ SWModule *SWMgr::CreateMod(const char *name, const char *driver, ConfigEntMap &s
if (compress) {
if (!stricmp(driver, "zText"))
- newmod = new zText(datapath.c_str(), name, description.c_str(), blockType, compress, 0, enc, direction, markup, lang.c_str());
- else newmod = new zCom(datapath.c_str(), name, description.c_str(), blockType, compress, 0, enc, direction, markup, lang.c_str());
+ newmod = new zText(datapath.c_str(), name, description.c_str(), blockType, compress, 0, enc, direction, markup, lang.c_str(), versification);
+ else newmod = new zCom(datapath.c_str(), name, description.c_str(), blockType, compress, 0, enc, direction, markup, lang.c_str(), versification);
}
}
if (!stricmp(driver, "RawText")) {
- newmod = new RawText(datapath.c_str(), name, description.c_str(), 0, enc, direction, markup, lang.c_str());
+ newmod = new RawText(datapath.c_str(), name, description.c_str(), 0, enc, direction, markup, lang.c_str(), versification);
}
if (!stricmp(driver, "RawText4")) {
- newmod = new RawText4(datapath.c_str(), name, description.c_str(), 0, enc, direction, markup, lang.c_str());
+ newmod = new RawText4(datapath.c_str(), name, description.c_str(), 0, enc, direction, markup, lang.c_str(), versification);
}
// backward support old drivers
@@ -814,11 +931,11 @@ SWModule *SWMgr::CreateMod(const char *name, const char *driver, ConfigEntMap &s
}
if (!stricmp(driver, "RawCom")) {
- newmod = new RawCom(datapath.c_str(), name, description.c_str(), 0, enc, direction, markup, lang.c_str());
+ newmod = new RawCom(datapath.c_str(), name, description.c_str(), 0, enc, direction, markup, lang.c_str(), versification);
}
if (!stricmp(driver, "RawCom4")) {
- newmod = new RawCom4(datapath.c_str(), name, description.c_str(), 0, enc, direction, markup, lang.c_str());
+ newmod = new RawCom4(datapath.c_str(), name, description.c_str(), 0, enc, direction, markup, lang.c_str(), versification);
}
if (!stricmp(driver, "RawFiles")) {
@@ -888,11 +1005,11 @@ SWModule *SWMgr::CreateMod(const char *name, const char *driver, ConfigEntMap &s
*/
}
- // if a specific module type is set in the config, use this
- if ((entry = section.find("Type")) != section.end())
- newmod->Type(entry->second.c_str());
+ if (newmod) {
+ // if a specific module type is set in the config, use this
+ if ((entry = section.find("Type")) != section.end())
+ newmod->Type(entry->second.c_str());
- if (newmod){
newmod->setConfig(&section);
}
diff --git a/src/mgr/versemgr.cpp b/src/mgr/versemgr.cpp
new file mode 100644
index 0000000..0673746
--- /dev/null
+++ b/src/mgr/versemgr.cpp
@@ -0,0 +1,369 @@
+/******************************************************************************
+ * versemgr.cpp - implementation of class VerseMgr used for managing
+ * versification systems
+ *
+ * $Id: versemgr.cpp 2108 2007-10-13 20:35:02Z scribe $
+ *
+ * Copyright 1998 CrossWire Bible Society (http://www.crosswire.org)
+ * CrossWire Bible Society
+ * P. O. Box 2528
+ * Tempe, AZ 85280-2528
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#include <versemgr.h>
+#include <vector>
+#include <map>
+#include <treekey.h>
+#include <canon.h> // KJV internal versification system
+#include <swlog.h>
+#include <algorithm>
+
+#include <canon_null.h> // null v11n system
+
+#include <canon_leningrad.h> // Leningrad Codex (WLC) v11n system
+#include <canon_mt.h> // Masoretic Text (MT) v11n system
+#include <canon_kjva.h> // KJV + Apocrypha v11n system
+#include <canon_nrsv.h> // NRSV v11n system
+#include <canon_nrsva.h> // NRSVA + Apocrypha v11n system
+
+using std::vector;
+using std::map;
+using std::distance;
+using std::lower_bound;
+
+SWORD_NAMESPACE_START
+
+
+VerseMgr *VerseMgr::getSystemVerseMgr() {
+ if (!systemVerseMgr) {
+ systemVerseMgr = new VerseMgr();
+ systemVerseMgr->registerVersificationSystem("KJV", otbooks, ntbooks, vm);
+ systemVerseMgr->registerVersificationSystem("Leningrad", otbooks_leningrad, ntbooks_null, vm_leningrad);
+ systemVerseMgr->registerVersificationSystem("MT", otbooks_mt, ntbooks_null, vm_mt);
+ systemVerseMgr->registerVersificationSystem("KJVA", otbooks_kjva, ntbooks, vm_kjva);
+ systemVerseMgr->registerVersificationSystem("NRSV", otbooks, ntbooks, vm_nrsv);
+ systemVerseMgr->registerVersificationSystem("NRSVA", otbooks_nrsva, ntbooks, vm_nrsva);
+ }
+ return systemVerseMgr;
+}
+
+
+class VerseMgr::System::Private {
+public:
+ /** Array[chapmax] of maximum verses in chapters */
+ vector<Book> books;
+ map<SWBuf, int> osisLookup;
+
+ Private() {
+ }
+ Private(const VerseMgr::System::Private &other) {
+ books = other.books;
+ osisLookup = other.osisLookup;
+ }
+ VerseMgr::System::Private &operator =(const VerseMgr::System::Private &other) {
+ books = other.books;
+ osisLookup = other.osisLookup;
+ return *this;
+ }
+};
+
+
+class VerseMgr::Book::Private {
+friend struct BookOffsetLess;
+public:
+ /** Array[chapmax] of maximum verses in chapters */
+ vector<int> verseMax;
+ vector<long> offsetPrecomputed;
+
+ Private() {
+ verseMax.clear();
+ }
+ Private(const VerseMgr::Book::Private &other) {
+ verseMax.clear();
+ verseMax = other.verseMax;
+ offsetPrecomputed = other.offsetPrecomputed;
+ }
+ VerseMgr::Book::Private &operator =(const VerseMgr::Book::Private &other) {
+ verseMax.clear();
+ verseMax = other.verseMax;
+ offsetPrecomputed = other.offsetPrecomputed;
+ return *this;
+ }
+};
+
+struct BookOffsetLess {
+ bool operator() (const VerseMgr::Book &o1, const VerseMgr::Book &o2) const { return o1.p->offsetPrecomputed[0] < o2.p->offsetPrecomputed[0]; }
+ bool operator() (const long &o1, const VerseMgr::Book &o2) const { return o1 < o2.p->offsetPrecomputed[0]; }
+ bool operator() (const VerseMgr::Book &o1, const long &o2) const { return o1.p->offsetPrecomputed[0] < o2; }
+ bool operator() (const long &o1, const long &o2) const { return o1 < o2; }
+};
+
+void VerseMgr::Book::init() {
+ p = new Private();
+}
+
+void VerseMgr::System::init() {
+ p = new Private();
+ BMAX[0] = 0;
+ BMAX[1] = 0;
+ ntStartOffset = 0;
+}
+
+
+VerseMgr::System::System(const System &other) {
+ init();
+ name = other.name;
+ BMAX[0] = other.BMAX[0];
+ BMAX[1] = other.BMAX[1];
+ (*p) = *(other.p);
+ ntStartOffset = other.ntStartOffset;
+}
+
+VerseMgr::System &VerseMgr::System::operator =(const System &other) {
+ name = other.name;
+ BMAX[0] = other.BMAX[0];
+ BMAX[1] = other.BMAX[1];
+ (*p) = *(other.p);
+ ntStartOffset = other.ntStartOffset;
+ return *this;
+}
+
+
+VerseMgr::System::~System() {
+ delete p;
+}
+
+const VerseMgr::Book *VerseMgr::System::getBook(int number) const {
+ return (number < (signed int)p->books.size()) ? &(p->books[number]) : 0;
+}
+
+
+int VerseMgr::System::getBookNumberByOSISName(const char *bookName) const {
+ map<SWBuf, int>::const_iterator it = p->osisLookup.find(bookName);
+ return (it != p->osisLookup.end()) ? it->second : -1;
+}
+
+
+void VerseMgr::System::loadFromSBook(const sbook *ot, const sbook *nt, int *chMax) {
+ int chap = 0;
+ int book = 0;
+ long offset = 0; // module heading
+ offset++; // testament heading
+ while (ot->chapmax) {
+ p->books.push_back(Book(ot->name, ot->osis, ot->prefAbbrev, ot->chapmax));
+ offset++; // book heading
+ Book &b = p->books[p->books.size()-1];
+ p->osisLookup[b.getOSISName()] = p->books.size();
+ for (int i = 0; i < ot->chapmax; i++) {
+ b.p->verseMax.push_back(chMax[chap]);
+ offset++; // chapter heading
+ b.p->offsetPrecomputed.push_back(offset);
+ offset += chMax[chap++];
+ }
+ ot++;
+ book++;
+ }
+ BMAX[0] = book;
+ book = 0;
+ ntStartOffset = offset;
+ offset++; // testament heading
+ while (nt->chapmax) {
+ p->books.push_back(Book(nt->name, nt->osis, nt->prefAbbrev, nt->chapmax));
+ offset++; // book heading
+ Book &b = p->books[p->books.size()-1];
+ p->osisLookup[b.getOSISName()] = p->books.size();
+ for (int i = 0; i < nt->chapmax; i++) {
+ b.p->verseMax.push_back(chMax[chap]);
+ offset++; // chapter heading
+ b.p->offsetPrecomputed.push_back(offset);
+ offset += chMax[chap++];
+ }
+ nt++;
+ book++;
+ }
+ BMAX[1] = book;
+
+ // TODO: build offset speed array
+}
+
+
+VerseMgr::Book::Book(const Book &other) {
+ longName = other.longName;
+ osisName = other.osisName;
+ prefAbbrev = other.prefAbbrev;
+ chapMax = other.chapMax;
+ init();
+ (*p) = *(other.p);
+}
+
+VerseMgr::Book& VerseMgr::Book::operator =(const Book &other) {
+ longName = other.longName;
+ osisName = other.osisName;
+ prefAbbrev = other.prefAbbrev;
+ chapMax = other.chapMax;
+ init();
+ (*p) = *(other.p);
+ return *this;
+}
+
+
+VerseMgr::Book::~Book() {
+ delete p;
+}
+
+
+int VerseMgr::Book::getVerseMax(int chapter) const {
+ chapter--;
+ return (p && (chapter < (signed int)p->verseMax.size()) && (chapter > -1)) ? p->verseMax[chapter] : -1;
+}
+
+
+int VerseMgr::System::getBookCount() const {
+ return (p ? p->books.size() : 0);
+}
+
+
+long VerseMgr::System::getOffsetFromVerse(int book, int chapter, int verse) const {
+ long offset = -1;
+ chapter--;
+
+ const Book *b = getBook(book);
+
+ if (!b) return -1; // assert we have a valid book
+ if ((chapter > -1) && (chapter >= (signed int)b->p->offsetPrecomputed.size())) return -1; // assert we have a valid chapter
+
+ offset = b->p->offsetPrecomputed[(chapter > -1)?chapter:0];
+ if (chapter < 0) offset--;
+
+/* old code
+ *
+ offset = offsets[testament-1][0][book];
+ offset = offsets[testament-1][1][(int)offset + chapter];
+ if (!(offset|verse)) // if we have a testament but nothing else.
+ offset = 1;
+
+*/
+
+ return (offset + verse);
+}
+
+
+char VerseMgr::System::getVerseFromOffset(long offset, int *book, int *chapter, int *verse) const {
+
+ if (offset < 1) { // just handle the module heading corner case up front (and error case)
+ (*book) = -1;
+ (*chapter) = 0;
+ (*verse) = 0;
+ return offset; // < 0 = error
+ }
+
+ // binary search for book
+ vector<Book>::iterator b = lower_bound(p->books.begin(), p->books.end(), offset, BookOffsetLess());
+ if (b == p->books.end()) b--;
+ (*book) = distance(p->books.begin(), b)+1;
+ if (offset < (*(b->p->offsetPrecomputed.begin()))-((((!(*book)) || (*book)==BMAX[0]+1))?2:1)) { // -1 for chapter headings
+ (*book)--;
+ if (b != p->books.begin()) {
+ b--;
+ }
+ }
+ vector<long>::iterator c = lower_bound(b->p->offsetPrecomputed.begin(), b->p->offsetPrecomputed.end(), offset);
+
+ // if we're a book heading, we are lessthan chapter precomputes, but greater book. This catches corner case.
+ if (c == b->p->offsetPrecomputed.end()) {
+ c--;
+ }
+ if ((offset < *c) && (c == b->p->offsetPrecomputed.begin())) {
+ (*chapter) = (offset - *c)+1; // should be 0 or -1 (for testament heading)
+ (*verse) = 0;
+ }
+ else {
+ if (offset < *c) c--;
+ (*chapter) = distance(b->p->offsetPrecomputed.begin(), c)+1;
+ (*verse) = (offset - *c);
+ }
+ return ((*chapter > 0) && (*verse > b->getVerseMax(*chapter))) ? KEYERR_OUTOFBOUNDS : 0;
+}
+
+
+/***************************************************
+ * VerseMgr
+ */
+
+class VerseMgr::Private {
+public:
+ Private() {
+ }
+ Private(const VerseMgr::Private &other) {
+ systems = other.systems;
+ }
+ VerseMgr::Private &operator =(const VerseMgr::Private &other) {
+ systems = other.systems;
+ return *this;
+ }
+ map<SWBuf, System> systems;
+};
+// ---------------- statics -----------------
+VerseMgr *VerseMgr::systemVerseMgr = 0;
+
+class __staticsystemVerseMgr {
+public:
+ __staticsystemVerseMgr() { }
+ ~__staticsystemVerseMgr() { delete VerseMgr::systemVerseMgr; }
+} _staticsystemVerseMgr;
+
+
+void VerseMgr::init() {
+ p = new Private();
+}
+
+
+VerseMgr::~VerseMgr() {
+ delete p;
+}
+
+
+void VerseMgr::setSystemVerseMgr(VerseMgr *newVerseMgr) {
+ if (systemVerseMgr)
+ delete systemVerseMgr;
+ systemVerseMgr = newVerseMgr;
+}
+
+
+const VerseMgr::System *VerseMgr::getVersificationSystem(const char *name) const {
+ map<SWBuf, System>::const_iterator it = p->systems.find(name);
+ return (it != p->systems.end()) ? &(it->second) : 0;
+}
+
+
+void VerseMgr::registerVersificationSystem(const char *name, const sbook *ot, const sbook *nt, int *chMax) {
+ p->systems[name] = name;
+ System &s = p->systems[name];
+ s.loadFromSBook(ot, nt, chMax);
+}
+
+
+void VerseMgr::registerVersificationSystem(const char *name, const TreeKey *tk) {
+}
+
+
+const StringList VerseMgr::getVersificationSystems() const {
+ StringList retVal;
+ for (map<SWBuf, System>::const_iterator it = p->systems.begin(); it != p->systems.end(); it++) {
+ retVal.push_back(it->first);
+ }
+ return retVal;
+}
+
+
+SWORD_NAMESPACE_END