diff options
Diffstat (limited to 'src/mgr')
-rw-r--r-- | src/mgr/Makefile.am | 2 | ||||
-rw-r--r-- | src/mgr/curlftpt.cpp | 20 | ||||
-rw-r--r-- | src/mgr/curlhttpt.cpp | 178 | ||||
-rw-r--r-- | src/mgr/encfiltmgr.cpp | 7 | ||||
-rw-r--r-- | src/mgr/filemgr.cpp | 4 | ||||
-rw-r--r-- | src/mgr/ftplibftpt.cpp | 19 | ||||
-rw-r--r-- | src/mgr/ftptrans.cpp | 23 | ||||
-rw-r--r-- | src/mgr/installmgr.cpp | 262 | ||||
-rw-r--r-- | src/mgr/localemgr.cpp | 33 | ||||
-rw-r--r-- | src/mgr/swconfig.cpp | 52 | ||||
-rw-r--r-- | src/mgr/swlocale.cpp | 104 | ||||
-rw-r--r-- | src/mgr/swmgr.cpp | 253 | ||||
-rw-r--r-- | src/mgr/versemgr.cpp | 369 |
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 §ion) { 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 §ion) { 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(§ion); } 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 |