Reinitialize gamepads command and fix EVDEV going bonkers on gamepad suddenly disconn...
[lsnes.git] / src / core / loadlib.cpp
blobad7ebf5a545ccc20823c388542f7272fe5a8264e
1 #include "core/command.hpp"
2 #include "core/dispatch.hpp"
3 #include "core/loadlib.hpp"
4 #include "core/messages.hpp"
5 #include "core/misc.hpp"
6 #include "interface/c-interface.hpp"
7 #include "interface/romtype.hpp"
8 #include "library/command.hpp"
9 #include "library/directory.hpp"
10 #include "library/filelist.hpp"
11 #include "library/loadlib.hpp"
12 #include "library/opus.hpp"
13 #include "library/running-executable.hpp"
15 #include <stdexcept>
16 #include <sstream>
17 #include <dirent.h>
19 namespace
21 std::map<unsigned, loadlib::module*> modules;
22 unsigned next_mod = 0;
24 std::string get_name(std::string path)
26 #if defined(_WIN32) || defined(_WIN64)
27 const char* sep = "\\/";
28 #else
29 const char* sep = "/";
30 #endif
31 size_t p = path.find_last_of(sep);
32 std::string name;
33 if(p == std::string::npos)
34 name = path;
35 else
36 name = path.substr(p + 1);
37 return name;
40 std::string get_user_library_dir()
42 return get_config_path() + "/autoload";
45 std::string get_system_library_dir()
47 std::string path;
48 try {
49 path = running_executable();
50 } catch(...) {
51 return "";
53 #if __WIN32__ || __WIN64__
54 const char* sep = "\\/";
55 #else
56 const char* sep = "/";
57 #endif
58 size_t p = path.find_last_of(sep);
59 if(p >= path.length())
60 path = ".";
61 else if(p == 0)
62 path = "/";
63 else
64 path = path.substr(0, p);
65 #if !__WIN32__ && !__WIN64__
66 //If executable is in /bin, translate library path to corresponding /lib/lsnes.
67 regex_results r = regex("(.*)/bin", path);
68 if(r) path = r[1] + "/lib/lsnes";
69 else
70 #endif
71 path = path + "/plugins";
72 return path;
76 void handle_post_loadlibrary()
78 if(new_core_flag) {
79 new_core_flag = false;
80 core_core::initialize_new_cores();
81 notify_new_core();
85 void with_loaded_library(const loadlib::module& l)
87 try {
88 if(!opus::libopus_loaded())
89 opus::load_libopus(l);
90 } catch(...) {
91 //This wasn't libopus.
93 try {
94 try_init_c_module(l);
95 } catch(...) {
96 //Ignored.
98 messages << "Loaded library '" << l.get_libname() << "'" << std::endl;
99 modules[next_mod++] = const_cast<loadlib::module*>(&l);
102 void with_unloaded_library(loadlib::module& l)
104 try {
105 try_uninit_c_module(l);
106 } catch(...) {
108 messages << "Unloading library '" << l.get_libname() << "'" << std::endl;
109 //Spot removed cores.
110 notify_new_core();
111 delete &l;
114 namespace
116 void load_libraries(std::set<std::string> libs, bool system,
117 void(*on_error)(const std::string& libname, const std::string& err, bool system))
119 std::set<std::string> blacklist;
120 std::set<std::string> killlist;
121 //System plugins can't be killlisted nor blacklisted.
122 if(!system) {
123 filelist _blacklist(get_user_library_dir() + "/blacklist", get_user_library_dir());
124 filelist _killlist(get_user_library_dir() + "/killlist", get_user_library_dir());
125 killlist = _killlist.enumerate();
126 blacklist = _blacklist.enumerate();
127 //Try to kill the libs that don't exist anymore.
128 for(auto i : libs)
129 if(killlist.count(get_name(i)))
130 remove(i.c_str());
131 killlist = _killlist.enumerate();
132 //All killlisted plugins are automatically blacklisted.
133 for(auto i : killlist)
134 blacklist.insert(i);
137 std::string extension = loadlib::library::extension();
138 for(auto i : libs) {
139 if(i.length() < extension.length() + 1)
140 continue;
141 if(i[i.length() - extension.length() - 1] != '.')
142 continue;
143 std::string tmp = i;
144 if(tmp.substr(i.length() - extension.length()) != extension)
145 continue;
146 if(blacklist.count(get_name(i)))
147 continue;
148 try {
149 with_loaded_library(*new loadlib::module(loadlib::library(i)));
150 } catch(std::exception& e) {
151 std::string x = "Can't load '" + i + "': " + e.what();
153 if(on_error)
154 on_error(get_name(i), e.what(), system);
155 messages << x << std::endl;
160 command::fnptr<const std::string&> CMD_unload_library(lsnes_cmds, "unload-library", "", "",
161 [](const std::string& args) throw(std::bad_alloc, std::runtime_error) {
162 unsigned libid = parse_value<unsigned>(args);
163 if(!modules.count(libid))
164 throw std::runtime_error("No such library loaded");
165 with_unloaded_library(*modules[libid]);
166 modules.erase(libid);
169 command::fnptr<> CMD_list_library(lsnes_cmds, "list-libraries", "", "",
170 []() throw(std::bad_alloc, std::runtime_error) {
171 for(auto i : modules)
172 messages << "#" << i.first << " [" << i.second->get_libname() << "]" << std::endl;
176 void autoload_libraries(void(*on_error)(const std::string& libname, const std::string& err, bool system))
178 try {
179 auto libs = directory::enumerate(get_user_library_dir(), ".*");
180 load_libraries(libs, false, on_error);
181 } catch(std::exception& e) {
182 messages << e.what() << std::endl;
184 try {
185 auto libs = directory::enumerate(get_system_library_dir(), ".*");
186 load_libraries(libs, true, on_error);
187 } catch(std::exception& e) {
188 messages << e.what() << std::endl;
190 handle_post_loadlibrary();