diff --git a/src/Config.cpp b/src/Config.cpp index 4376085e..eee6e067 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -171,8 +171,7 @@ class ConfigInternal { return chain; } - std::string FindConfigFile(std::string fileName, - const std::vector& configPaths) { + std::string FindConfigFile(std::string fileName) { std::ifstream ifs; // Working directory @@ -194,7 +193,7 @@ class ConfigInternal { } } - for (const std::string& dirPath : configPaths) { + for (const std::string& dirPath : paths) { std::string path = dirPath + '/' + fileName; ifs.open(UTF8Util::GetPlatformString(path).c_str()); if (ifs.is_open()) { @@ -205,16 +204,39 @@ class ConfigInternal { throw FileNotFound(fileName); } }; + +std::string GetParentDirectory(const std::string& path) { + size_t pos = path.rfind('/', path.length() - 1); + if (pos == std::string::npos) { + pos = path.rfind('\\', path.length() - 1); + } + if (pos == std::string::npos) { + return ""; + } + return path.substr(0, pos + 1); +} + } // namespace Config::Config() : internal(new ConfigInternal()) {} -Config::~Config() { delete (ConfigInternal*)internal; } +Config::~Config() { delete reinterpret_cast(internal); } ConverterPtr Config::NewFromFile(const std::string& fileName, - const std::vector& paths) { - ConfigInternal* impl = (ConfigInternal*)internal; - std::string prefixedFileName = impl->FindConfigFile(fileName, paths); + const std::vector& paths, + const char* argv0) { + ConfigInternal* impl = reinterpret_cast(internal); + impl->paths = paths; + if (argv0 != nullptr) { + std::string parent = GetParentDirectory(argv0); + if (!parent.empty()) { + impl->paths.push_back(parent); + } + } + if (PACKAGE_DATA_DIRECTORY != "") { + impl->paths.push_back(PACKAGE_DATA_DIRECTORY); + } + std::string prefixedFileName = impl->FindConfigFile(fileName); std::ifstream ifs(UTF8Util::GetPlatformString(prefixedFileName)); std::string content(std::istreambuf_iterator(ifs), (std::istreambuf_iterator())); @@ -227,11 +249,10 @@ ConverterPtr Config::NewFromFile(const std::string& fileName, if (slashPos != std::string::npos) { configDirectory = prefixedFileName.substr(0, slashPos) + "/"; } - std::vector dictPaths = paths; if (!configDirectory.empty()) { - dictPaths.push_back(configDirectory); + impl->paths.push_back(configDirectory); } - return NewFromString(content, dictPaths); + return NewFromString(content, impl->paths); } ConverterPtr Config::NewFromString(const std::string& json, @@ -265,11 +286,8 @@ ConverterPtr Config::NewFromString(const std::string& json, name = doc["name"].GetString(); } - ConfigInternal* impl = (ConfigInternal*)internal; + ConfigInternal* impl = reinterpret_cast(internal); impl->paths = paths; - if (PACKAGE_DATA_DIRECTORY != "") { - impl->paths.push_back(PACKAGE_DATA_DIRECTORY); - } // Required: segmentation SegmentationPtr segmentation = diff --git a/src/Config.hpp b/src/Config.hpp index 2b66d173..1737d01b 100644 --- a/src/Config.hpp +++ b/src/Config.hpp @@ -38,7 +38,8 @@ class OPENCC_EXPORT Config { const std::vector& paths); ConverterPtr NewFromFile(const std::string& fileName, - const std::vector& paths = {}); + const std::vector& paths = {}, + const char* argv0 = nullptr); private: void* internal; diff --git a/src/SimpleConverter.cpp b/src/SimpleConverter.cpp index a1b4ac96..7b24ac65 100644 --- a/src/SimpleConverter.cpp +++ b/src/SimpleConverter.cpp @@ -36,21 +36,29 @@ struct InternalData { InternalData(const ConverterPtr& _converter) : converter(_converter) {} static InternalData* NewInternalData(const std::string& configFileName, - const std::vector& paths) { + const std::vector& paths, + const char* argv0) { try { Config config; #ifdef BAZEL - std::unique_ptr bazel_runfiles(Runfiles::Create("")); - std::vector paths_with_runfiles = paths; - paths_with_runfiles.push_back( - bazel_runfiles->Rlocation("_main/data/config")); - paths_with_runfiles.push_back( - bazel_runfiles->Rlocation("_main/data/dictionary")); - return new InternalData( - config.NewFromFile(configFileName, paths_with_runfiles)); -#else - return new InternalData(config.NewFromFile(configFileName, paths)); + std::string err; + std::unique_ptr bazel_runfiles( + Runfiles::Create(argv0 != nullptr ? argv0 : "", &err)); + if (bazel_runfiles != nullptr) { + std::vector paths_with_runfiles = paths; + paths_with_runfiles.push_back( + bazel_runfiles->Rlocation("opencc~/data/config")); + paths_with_runfiles.push_back( + bazel_runfiles->Rlocation("opencc~/data/dictionary")); + paths_with_runfiles.push_back( + bazel_runfiles->Rlocation("_main/data/config")); + paths_with_runfiles.push_back( + bazel_runfiles->Rlocation("_main/data/dictionary")); + return new InternalData( + config.NewFromFile(configFileName, paths_with_runfiles)); + } #endif + return new InternalData(config.NewFromFile(configFileName, paths, argv0)); } catch (Exception& ex) { throw std::runtime_error(ex.what()); } @@ -64,7 +72,13 @@ SimpleConverter::SimpleConverter(const std::string& configFileName) SimpleConverter::SimpleConverter(const std::string& configFileName, const std::vector& paths) - : internalData(InternalData::NewInternalData(configFileName, paths)) {} + : SimpleConverter(configFileName, paths, nullptr) {} + +SimpleConverter::SimpleConverter(const std::string& configFileName, + const std::vector& paths, + const char* argv0) + : internalData( + InternalData::NewInternalData(configFileName, paths, argv0)) {} SimpleConverter::~SimpleConverter() { delete (InternalData*)internalData; } diff --git a/src/SimpleConverter.hpp b/src/SimpleConverter.hpp index 57e88cd6..c7cda2bf 100644 --- a/src/SimpleConverter.hpp +++ b/src/SimpleConverter.hpp @@ -52,6 +52,16 @@ class OPENCC_EXPORT SimpleConverter { SimpleConverter(const std::string& configFileName, const std::vector& paths); + /** + * Constructor of SimpleConverter + * @param configFileName File name of configuration. + * @param paths Additional paths to locate configuration and dictionary files. + * @param argv0 Path of the executable (argv[0]), in addition to additional + * paths. + */ + SimpleConverter(const std::string& configFileName, + const std::vector& paths, const char* argv0); + ~SimpleConverter(); /**