bsnes: redump sprite/palette functions
[lsnes.git] / src / library / loadlib.cpp
blob7ffab4016f07c6deb75a0afc6b4a576f38751ffd
1 #include "loadlib.hpp"
2 #include <sstream>
3 #include <list>
5 #if !defined(NO_DLFCN) && !defined(_WIN32) && !defined(_WIN64)
6 #include <dlfcn.h>
7 #include <unistd.h>
8 #endif
10 namespace loadlib
12 mutex_class& global_mutex()
14 static mutex_class m;
15 return m;
18 namespace
20 #if defined(_WIN32) || defined(_WIN64)
21 std::string callsign = "dynamic link library";
22 std::string callsign_ext = "dll";
23 #elif !defined(NO_DLFCN)
24 #if defined(__APPLE__)
25 std::string callsign = "dynamic library";
26 std::string callsign_ext = "bundle";
27 #else
28 std::string callsign = "shared object";
29 std::string callsign_ext = "so";
30 #endif
31 #else
32 std::string callsign = "";
33 #endif
36 library::internal::internal(const std::string& filename) throw(std::bad_alloc, std::runtime_error)
38 refs = 1;
39 #if !defined(NO_DLFCN) && !defined(_WIN32) && !defined(_WIN64)
40 char buffer[16384];
41 getcwd(buffer, 16383);
42 std::string _filename = filename;
43 if(filename.find_first_of("/") >= filename.length())
44 _filename = buffer + std::string("/") + filename;
45 handle = dlopen(_filename.c_str(), RTLD_LOCAL | RTLD_NOW);
46 if(!handle)
47 throw std::runtime_error(dlerror());
48 #elif defined(_WIN32) || defined(_WIN64)
49 char buffer[16384];
50 GetCurrentDirectory(16383, buffer);
51 std::string _filename = filename;
52 if(filename.find_first_of("/\\") >= filename.length())
53 _filename = buffer + std::string("/") + filename;
54 handle = LoadLibraryA(_filename.c_str());
55 if(!handle) {
56 int errcode = GetLastError();
57 char errorbuffer[1024];
58 if(FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, NULL, errcode, 0,
59 errorbuffer, sizeof(errorbuffer), NULL))
60 throw std::runtime_error(errorbuffer);
61 else {
62 std::ostringstream str;
63 str << "Unknown system error (code " << errcode << ")";
64 throw std::runtime_error(str.str());
67 #else
68 throw std::runtime_error("Loading libraries is not supported");
69 #endif
72 library::internal::~internal() throw()
74 #if !defined(NO_DLFCN) && !defined(_WIN32) && !defined(_WIN64)
75 dlclose(handle);
76 #elif defined(_WIN32) || defined(_WIN64)
77 FreeLibrary(handle);
78 #endif
81 void* library::internal::operator[](const std::string& symbol) const throw(std::bad_alloc, std::runtime_error)
83 #if !defined(NO_DLFCN) && !defined(_WIN32) && !defined(_WIN64)
84 dlerror();
85 void* s = dlsym(handle, symbol.c_str());
86 if(s)
87 return s;
88 char* e = dlerror();
89 if(e)
90 throw std::runtime_error(e);
91 return NULL; //Yes, real NULL symbol.
92 #elif defined(_WIN32) || defined(_WIN64)
93 void* s = (void*)GetProcAddress(handle, symbol.c_str());
94 if(s)
95 return s;
96 int errcode = GetLastError();
97 char errorbuffer[1024];
98 if(FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, NULL, errcode, 0,
99 errorbuffer, sizeof(errorbuffer), NULL))
100 throw std::runtime_error(errorbuffer);
101 else {
102 std::ostringstream str;
103 str << "Unknown system error (code " << errcode << ")";
104 throw std::runtime_error(str.str());
106 #else
107 throw std::runtime_error("Library loading not supported");
108 #endif
111 const std::string& library::name() throw()
113 return callsign;
116 const std::string& library::extension() throw()
118 return callsign_ext;
121 namespace
123 std::list<loadlib::module*>& module_queue()
125 static std::list<module*> x;
126 return x;
130 module::module(std::initializer_list<symbol> _symbols, std::function<void(const module&)> init_fn)
132 dynamic = false;
133 for(auto i : _symbols)
134 symbols[i.name] = i.address;
135 init = init_fn;
136 if(init) {
137 umutex_class h(global_mutex());
138 module_queue().push_back(this);
142 module::module(library _lib)
144 dynamic = true;
145 lib = _lib;
148 module::~module()
150 umutex_class h(global_mutex());
151 for(auto i = module_queue().begin(); i != module_queue().end(); i++) {
152 if(*i == this) {
153 module_queue().erase(i);
154 break;
159 module::module(const module& mod)
161 dynamic = mod.dynamic;
162 lib = mod.lib;
163 symbols = mod.symbols;
164 init = mod.init;
165 if(init) {
166 umutex_class h(global_mutex());
167 module_queue().push_back(this);
171 void* module::operator[](const std::string& symbol) const throw(std::bad_alloc, std::runtime_error)
173 if(dynamic)
174 return lib[symbol];
175 else if(symbols.count(symbol))
176 return symbols.find(symbol)->second;
177 else
178 throw std::runtime_error("Symbol '" + symbol + "' not found");
181 void module::run_initializers()
183 for(auto i : module_queue())
184 if(i->init) {
185 i->init(*i);
186 i->init = std::function<void(const module&)>();
188 module_queue().clear();