// // plugin.hpp // plugins // // Created by Bob Polis at 2019-06-09 // Copyright (c) 2019 SwiftCoder. All rights reserved. // #ifndef _plugin_H_ #define _plugin_H_ #include #include #include #include #include #include #include namespace sc { template class plugin { public: static void scan_plugins(const std::string& dir, const std::string& ext) { DIR* plugins_dir = ::opendir(dir.c_str()); throw_if_null_msg(plugins_dir, (dir + " could not be opened").c_str()); struct dirent* info; while ((info = ::readdir(plugins_dir)) != nullptr) { if (info->d_name[0] != '.') { std::string plugname {info->d_name}; std::string::size_type lastdot = plugname.rfind("."); if (plugname.substr(lastdot + 1) == ext) { } plugin plugin {dir + '/' + plugname}; plugins.emplace(plugname.substr(0, lastdot), std::move(plugin)); } } throw_if_min1(::closedir(plugins_dir)); } using processor = std::function; static void foreach(processor proc) { for (const auto& elem : plugins) { proc(elem.second); } } static plugin& get(const std::string& name) { return plugins.at(name); } static std::vector names() { std::vector result; for (const auto& elem : plugins) { result.emplace_back(elem.first); } return result; } plugin(const std::string& path) : _path {path} { _plugin = ::dlopen(path.c_str(), RTLD_LAZY); //std::cerr << path << (_plugin ? "" : " not") << " opened\n"; const char* err {::dlerror()}; if (err) std::cerr << err << '\n'; if (_plugin) { _factory = reinterpret_cast(::dlsym(_plugin, "create_instance")); if (!_factory) { std::cerr << "create_instance() function not found in " << path << '\n'; } } } ~plugin() { if (_plugin) { ::dlclose(_plugin); _plugin = nullptr; //std::cerr << _path << " closed\n"; } } plugin(const plugin&) = delete; plugin& operator=(const plugin&) = delete; plugin(plugin&& other) { _path = other._path; _plugin = other._plugin; _factory = other._factory; other._plugin = nullptr; } plugin& operator=(plugin&& other) { if (this != &other) { _path = other._path; _plugin = other._plugin; _factory = other._factory; other._plugin = nullptr; } return *this; } std::string path() const { return _path; } std::unique_ptr operator()() const { std::unique_ptr obj; if (_factory) { obj.reset(_factory()); } return obj; } private: static std::map> plugins; std::string _path; void* _plugin {nullptr}; using factory = T*(*)(); factory _factory {nullptr}; }; template std::map> plugin::plugins; } #endif // _plugin_H_