diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 02fa1d7651..9f70fac15e 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -157,6 +157,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat engine.enableFSStrict(variables["fs-strict"].as()); Files::PathContainer dataDirs(variables["data"].as()); + cfgMgr.processPaths(dataDirs); std::string local(variables["data-local"].as()); if (!local.empty()) @@ -166,7 +167,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat if (dataDirs.empty()) { - dataDirs.push_back(cfgMgr.getDataPath(Files::localDataToken)); + dataDirs.push_back(cfgMgr.getLocalDataPath()); } engine.setDataDirs(dataDirs); diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index aaa26977c5..e1bf48a6fc 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include namespace Files { @@ -24,7 +24,7 @@ ConfigurationManager::ConfigurationManager() /** * According to task #168 plugins.cfg file shall be located in global - * configuration path or in runtime configuration path. + * configuration path or in local configuration path. */ mPluginsCfgPath = mFixedPath.getGlobalPath() / pluginsCfgFile; if (!boost::filesystem::is_regular_file(mPluginsCfgPath)) @@ -55,10 +55,10 @@ ConfigurationManager::~ConfigurationManager() void ConfigurationManager::setupTokensMapping() { - mTokensMapping.insert(std::make_pair(mwDataToken, &FixedPath<>::getInstallPath)); - mTokensMapping.insert(std::make_pair(localDataToken, &FixedPath<>::getLocalDataPath)); - mTokensMapping.insert(std::make_pair(userDataToken, &FixedPath<>::getUserDataPath)); - mTokensMapping.insert(std::make_pair(globalDataToken, &FixedPath<>::getGlobalDataPath)); + mTokensMapping.insert(std::make_pair(mwDataToken, &FixedPath<>::setInstallPath)); + mTokensMapping.insert(std::make_pair(localDataToken, &FixedPath<>::setLocalDataPath)); + mTokensMapping.insert(std::make_pair(userDataToken, &FixedPath<>::setUserDataPath)); + mTokensMapping.insert(std::make_pair(globalDataToken, &FixedPath<>::setGlobalDataPath)); } void ConfigurationManager::readConfiguration(boost::program_options::variables_map& variables, @@ -66,10 +66,54 @@ void ConfigurationManager::readConfiguration(boost::program_options::variables_m { loadConfig(mFixedPath.getUserPath(), variables, description); boost::program_options::notify(variables); + loadConfig(mFixedPath.getLocalPath(), variables, description); boost::program_options::notify(variables); loadConfig(mFixedPath.getGlobalPath(), variables, description); boost::program_options::notify(variables); + +} + +struct EmptyPath : public std::unary_function +{ + bool operator()(const boost::filesystem::path& path) const + { + return path.empty(); + } +}; + +void ConfigurationManager::processPaths(Files::PathContainer& dataDirs) +{ + for (Files::PathContainer::iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) + { + const std::string& path = it->string(); + if (!path.empty() && path[0] == '?') + { + std::string::size_type pos = path.find('?', 1); + if (pos != std::string::npos) + { + ++pos; + TokensMappingContainer::iterator tokenIt = mTokensMapping.find(path.substr(0, pos)); + + if (tokenIt != mTokensMapping.end()) + { + boost::filesystem::path tempPath(path.substr(pos, path.length() - pos)); + + if (boost::filesystem::is_directory(tempPath)) + { + ((mFixedPath).*(tokenIt->second))(tempPath); + (*it) = tempPath; + } + else + { + (*it).clear(); + } + } + } + } + } + + dataDirs.erase(std::remove_if(dataDirs.begin(), dataDirs.end(), EmptyPath()), dataDirs.end()); } void ConfigurationManager::loadConfig(const boost::filesystem::path& path, @@ -112,17 +156,26 @@ const boost::filesystem::path& ConfigurationManager::getLocalPath() const return mFixedPath.getLocalPath(); } -const boost::filesystem::path& ConfigurationManager::getDataPath(const std::string& type) const +const boost::filesystem::path& ConfigurationManager::getGlobalDataPath() const { - TokensMappingContainer::const_iterator it = mTokensMapping.find(type); - if (it != mTokensMapping.end()) - { - return ((mFixedPath).*(it->second))(); - } + return mFixedPath.getGlobalDataPath(); +} + +const boost::filesystem::path& ConfigurationManager::getUserDataPath() const +{ + return mFixedPath.getUserDataPath(); +} +const boost::filesystem::path& ConfigurationManager::getLocalDataPath() const +{ return mFixedPath.getLocalDataPath(); } +const boost::filesystem::path& ConfigurationManager::getInstallPath() const +{ + return mFixedPath.getInstallPath(); +} + const boost::filesystem::path& ConfigurationManager::getOgreConfigPath() const { return mOgreCfgPath; diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp index d1c9999793..dce56ea5d5 100644 --- a/components/files/configurationmanager.hpp +++ b/components/files/configurationmanager.hpp @@ -7,6 +7,7 @@ #include #include +#include /** * \namespace Files @@ -14,12 +15,6 @@ namespace Files { -extern const char* const mwDataToken; -extern const char* const localDataToken; -extern const char* const userDataToken; -extern const char* const globalDataToken; - - /** * \struct ConfigurationManager */ @@ -30,13 +25,17 @@ struct ConfigurationManager void readConfiguration(boost::program_options::variables_map& variables, boost::program_options::options_description& description); + void processPaths(Files::PathContainer& dataDirs); /**< Fixed paths */ const boost::filesystem::path& getGlobalPath() const; const boost::filesystem::path& getUserPath() const; - const boost::filesystem::path& getLocalPath() const ; + const boost::filesystem::path& getLocalPath() const; - const boost::filesystem::path& getDataPath(const std::string& type) const; + const boost::filesystem::path& getGlobalDataPath() const; + const boost::filesystem::path& getUserDataPath() const; + const boost::filesystem::path& getLocalDataPath() const; + const boost::filesystem::path& getInstallPath() const; const boost::filesystem::path& getOgreConfigPath() const; const boost::filesystem::path& getPluginsConfigPath() const; @@ -45,7 +44,7 @@ struct ConfigurationManager private: typedef Files::FixedPath<> FixedPathType; - typedef const boost::filesystem::path& (FixedPathType::*path_type_f)() const; + typedef void (FixedPathType::*path_type_f)(const boost::filesystem::path&); typedef std::tr1::unordered_map TokensMappingContainer; void loadConfig(const boost::filesystem::path& path, diff --git a/components/files/fixedpath.hpp b/components/files/fixedpath.hpp index 3a27bd21d4..3db409b2c2 100644 --- a/components/files/fixedpath.hpp +++ b/components/files/fixedpath.hpp @@ -122,11 +122,12 @@ struct FixedPath const boost::filesystem::path& getInstallPath() const { - // TODO: It will be corrected later. - static boost::filesystem::path p("./"); - return p; + return mInstallPath; + } - //return mFixedPath.getInstallPath(); + void setInstallPath(const boost::filesystem::path& path) + { + mInstallPath = path; } const boost::filesystem::path& getGlobalDataPath() const @@ -134,16 +135,31 @@ struct FixedPath return mGlobalDataPath; } + void setGlobalDataPath(const boost::filesystem::path& path) + { + mGlobalDataPath = path; + } + const boost::filesystem::path& getUserDataPath() const { return mUserDataPath; } + void setUserDataPath(const boost::filesystem::path& path) + { + mUserDataPath = path; + } + const boost::filesystem::path& getLocalDataPath() const { return mLocalDataPath; } + void setLocalDataPath(const boost::filesystem::path& path) + { + mLocalDataPath = path; + } + private: PathType mPath; diff --git a/components/files/linuxpath.cpp b/components/files/linuxpath.cpp index a1d1168d9a..41891661ef 100644 --- a/components/files/linuxpath.cpp +++ b/components/files/linuxpath.cpp @@ -157,73 +157,75 @@ boost::filesystem::path LinuxPath::getLocalDataPath() const boost::filesystem::path LinuxPath::getInstallPath() const { + boost::filesystem::path installPath; + char *homePath = getenv("HOME"); - if(!homePath) - { - return boost::filesystem::path(""); - } - - boost::filesystem::path wineDefaultRegistry(homePath); - wineDefaultRegistry /= ".wine/system.reg"; - - boost::filesystem::path wineDriveC(homePath); - wineDriveC /= ".wine/drive_c"; - - boost::filesystem::file_status fileStatus = boost::filesystem::status(wineDefaultRegistry); - boost::filesystem::file_status dirStatus = boost::filesystem::status(wineDriveC); - if(!boost::filesystem::is_regular_file(fileStatus) || !boost::filesystem::is_directory(dirStatus)) + if (homePath == NULL) { - return boost::filesystem::path(""); - } - - - boost::filesystem::ifstream file(wineDefaultRegistry); - bool isRegEntry = false; - std::string line; - - while (std::getline(file, line)) - { - if(!line.empty() && line[0] == '[') // we found an entry + struct passwd* pwd = getpwuid(getuid()); + if (pwd != NULL) { - std::string regkey = line.substr(1, line.find(']')-1); - if( regkey.compare("SOFTWARE\\\\Wow6432Node\\\\Bethesda Softworks\\\\Morrowind") == 0 - || regkey.compare("SOFTWARE\\\\Bethesda Softworks\\\\Morrowind") == 0 ) - { - isRegEntry = true; - } + homePath = pwd->pw_dir; } - else if(isRegEntry) + } + + if (homePath != NULL) + { + boost::filesystem::path wineDefaultRegistry(homePath); + wineDefaultRegistry /= ".wine/system.reg"; + + if (boost::filesystem::is_regular_file(wineDefaultRegistry)) { - if(line.empty() || line[0] != '"') // empty line means new registry key + boost::filesystem::ifstream file(wineDefaultRegistry); + bool isRegEntry = false; + std::string line; + std::string mwpath; + + while (std::getline(file, line) && !line.empty()) { - break; - } - std::string key = line.substr(1, line.find('"', 1)-1); - if(key.compare("Installed Path") == 0) { - std::string::size_type pos, startPos; - - startPos = line.find('=')+2; - std::string installPath = line.substr(startPos, line.find('"', startPos+1)-startPos); - installPath.replace(0, 2, wineDriveC.string()); - - pos = -1; - do + if (line[0] == '[') // we found an entry + { + isRegEntry = (line.find("Softworks\\Morrowind]") != std::string::npos); + } + else if (isRegEntry) { - pos = installPath.find("\\\\", pos+1); - if(pos == std::string::npos) + if (line[0] == '"') // empty line means new registry key { - break; + std::string key = line.substr(1, line.find('"', 1) - 1); + if (strcasecmp(key.c_str(), "Installed Path") == 0) + { + std::string::size_type valuePos = line.find('=') + 2; + mwpath = line.substr(valuePos, line.rfind('"') - valuePos); + + std::string::size_type pos = mwpath.find("\\"); + while (pos != std::string::npos) + { + mwpath.replace(pos, 2, "/"); + pos = mwpath.find("\\", pos + 1); + } + break; + } } - - installPath.replace(pos, 2, "/"); - } while(true); - - return boost::filesystem::path(installPath); + } + } + + if (!mwpath.empty()) + { + // Change drive letter to lowercase, so we could use ~/.wine/dosdevice symlinks + mwpath[0] = tolower(mwpath[0]); + installPath /= homePath; + installPath /= ".wine/dosdevices/"; + installPath /= mwpath; + + if (!boost::filesystem::is_directory(installPath)) + { + installPath.clear(); + } } } } - - return boost::filesystem::path(""); + + return installPath; } } /* namespace Files */ diff --git a/components/files/macospath.cpp b/components/files/macospath.cpp index 87ac422020..789c877099 100644 --- a/components/files/macospath.cpp +++ b/components/files/macospath.cpp @@ -112,11 +112,83 @@ boost::filesystem::path MacOsPath::getLocalDataPath() const return boost::filesystem::path("./data/"); } -boost::filesystem::path MacOsPath::getInstallPath() const; +/** + * FIXME: This should be verified on MacOS system! + */ +boost::filesystem::path MacOsPath::getInstallPath() const { - return boost::filesystem::path("./"); + boost::filesystem::path installPath; + + char *homePath = getenv("HOME"); + if (homePath == NULL) + { + struct passwd* pwd = getpwuid(getuid()); + if (pwd != NULL) + { + homePath = pwd->pw_dir; + } + } + + if (homePath != NULL) + { + boost::filesystem::path wineDefaultRegistry(homePath); + wineDefaultRegistry /= ".wine/system.reg"; + + if (boost::filesystem::is_regular_file(wineDefaultRegistry)) + { + boost::filesystem::ifstream file(wineDefaultRegistry); + bool isRegEntry = false; + std::string line; + std::string mwpath; + + while (std::getline(file, line) && !line.empty()) + { + if (line[0] == '[') // we found an entry + { + isRegEntry = (line.find("Softworks\\Morrowind]") != std::string::npos); + } + else if (isRegEntry) + { + if (line[0] == '"') // empty line means new registry key + { + std::string key = line.substr(1, line.find('"', 1) - 1); + if (strcasecmp(key.c_str(), "Installed Path") == 0) + { + std::string::size_type valuePos = line.find('=') + 2; + mwpath = line.substr(valuePos, line.rfind('"') - valuePos); + + std::string::size_type pos = mwpath.find("\\"); + while (pos != std::string::npos) + { + mwpath.replace(pos, 2, "/"); + pos = mwpath.find("\\", pos + 1); + } + break; + } + } + } + } + + if (!mwpath.empty()) + { + // Change drive letter to lowercase, so we could use ~/.wine/dosdevice symlinks + mwpath[0] = tolower(mwpath[0]); + installPath /= homePath; + installPath /= ".wine/dosdevices/"; + installPath /= mwpath; + + if (!boost::filesystem::is_directory(installPath)) + { + installPath.clear(); + } + } + } + } + + return installPath; } + } /* namespace Files */ #endif /* defined(macintosh) || defined(Macintosh) || defined(__APPLE__) || defined(__MACH__) */