Last active
January 19, 2020 12:02
-
-
Save untodesu/79c87029318d2a03b9878788ed3c7515 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // interface.h implementation shit | |
| #include <cstring> // strcmp, strncpy | |
| #include "platform.h" | |
| #include "interface.h" | |
| #ifdef _WIN32 | |
| #include <Windows.h> | |
| static constexpr char FS_CORRECT_SEP = '\\'; | |
| static constexpr char FS_INVALID_SEP = '/'; | |
| #else | |
| // OSX? uh oh, maybe | |
| #include <dlfcn.h> | |
| static constexpr char FS_CORRECT_SEP = '/'; | |
| static constexpr char FS_INVALID_SEP = '\\'; | |
| #endif | |
| //----------------------------------------------------------------------------- | |
| // FixSlashes | |
| // Replaces all incorrect (platform-specific) directory separators with | |
| // correct (platform-specific) ones. | |
| //----------------------------------------------------------------------------- | |
| static void FixSlashes(char *sp, char sep = FS_CORRECT_SEP) | |
| { | |
| if(!sp) { | |
| // Passing nullptr will result nothing | |
| return; | |
| } | |
| while(*sp) { | |
| if(*sp == FS_INVALID_SEP || *sp == FS_CORRECT_SEP) { | |
| *sp = sep; | |
| } | |
| sp++; | |
| } | |
| } | |
| //----------------------------------------------------------------------------- | |
| // InterfaceReg::s_listHead - global list head | |
| //----------------------------------------------------------------------------- | |
| InterfaceReg * InterfaceReg::s_listHead = nullptr; | |
| //----------------------------------------------------------------------------- | |
| // InterfaceReg::InterfaceReg | |
| // Constructor, adds new interface to the global list | |
| //----------------------------------------------------------------------------- | |
| InterfaceReg::InterfaceReg(instanceInterface_ft instanceFn, const char *name) : m_instanceFn(instanceFn), m_name(name) | |
| { | |
| m_listNext = s_listHead; | |
| s_listHead = this; | |
| } | |
| //----------------------------------------------------------------------------- | |
| // CreateInterfaceInternal | |
| // Internal implementation of createInterface_ft | |
| //----------------------------------------------------------------------------- | |
| static IBaseInterface * CreateInterfaceInternal(const char *name) | |
| { | |
| for(InterfaceReg *icur = InterfaceReg::s_listHead; icur; icur = icur->m_listNext) { | |
| if(!strcmp(icur->m_name, name)) { | |
| return icur->m_instanceFn(); | |
| } | |
| } | |
| return nullptr; | |
| } | |
| //----------------------------------------------------------------------------- | |
| // G_CreateInterface | |
| // Global variant of CreateInterfaceInternal. Used by Sys_Getfactory | |
| //----------------------------------------------------------------------------- | |
| DLL_EXPORT IBaseInterface * G_CreateInterface(const char *name) | |
| { | |
| // stub stub stub | |
| return CreateInterfaceInternal(name); | |
| } | |
| //----------------------------------------------------------------------------- | |
| // GetModuleHandleA | |
| // POSIX-Only, emulates winapi's function | |
| //----------------------------------------------------------------------------- | |
| #ifndef _WIN32 | |
| static void * GetModuleHandleA(const char *filename) | |
| { | |
| if(!filename) { | |
| // we don't need to use THIS module, so it's here | |
| return nullptr; | |
| } | |
| void *hnd = dlopen(filename, RTLD_NOW); | |
| if(!hnd) { | |
| // print some error things HERE | |
| return nullptr; | |
| } | |
| dlclose(hnd); | |
| return (void *)hnd; | |
| } | |
| #endif | |
| //----------------------------------------------------------------------------- | |
| // Sys_GetModuleHandle | |
| // Wraps GetModuleHandleA | |
| //----------------------------------------------------------------------------- | |
| static module_t Sys_GetModuleHandle(const char *filename) | |
| { | |
| // Fix existing slashes | |
| const size_t fnlen = strlen(filename); | |
| char *filenameFixed = new char[fnlen]; | |
| strncpy(filenameFixed, filename, fnlen); | |
| FixSlashes(filenameFixed); | |
| // Actually load(?) module | |
| module_t m = (module_t)GetModuleHandleA(filenameFixed); | |
| delete[] filenameFixed; | |
| return m; | |
| } | |
| //----------------------------------------------------------------------------- | |
| // Sys_GetProcAddress <- module_t, const char * | |
| // Returns a pointer to DLL_EXPORT thing | |
| //----------------------------------------------------------------------------- | |
| void * Sys_GetProcAddress(module_t m, const char *proc) | |
| { | |
| #ifdef _WIN32 | |
| return (void *)GetProcAddress((HMODULE)m, proc); | |
| #else | |
| return dlsym((void *)m, proc); | |
| #endif | |
| } | |
| //----------------------------------------------------------------------------- | |
| // Sys_GetProcAddress <- const char *, const char * | |
| // Returns a pointer to DLL_EXPORT thing | |
| //----------------------------------------------------------------------------- | |
| void * Sys_GetProcAddress(const char *filename, const char *proc) | |
| { | |
| module_t m = Sys_GetModuleHandle(filename); | |
| #ifdef _WIN32 | |
| // new windows.h throws a warning about this that O_o | |
| if(m) { | |
| return (void *)GetProcAddress((HMODULE)m, proc); | |
| } | |
| #else | |
| return dlsym((void *)m, proc); | |
| #endif | |
| // again, winapi | |
| return nullptr; | |
| } | |
| //----------------------------------------------------------------------------- | |
| // Sys_LoadModule | |
| // Loads module from specified file, or don't loads :P | |
| //----------------------------------------------------------------------------- | |
| module_t Sys_LoadModule(const char *filename) | |
| { | |
| return Sys_GetModuleHandle(filename); | |
| } | |
| //----------------------------------------------------------------------------- | |
| // Sys_UnloadModule | |
| // Un-Loads module | |
| //----------------------------------------------------------------------------- | |
| void Sys_UnloadModule(module_t m) | |
| { | |
| if(!m) { | |
| return; | |
| } | |
| #ifdef _WIN32 | |
| FreeLibrary((HMODULE)m); | |
| #else | |
| dlclose((void *)m); | |
| #endif | |
| } | |
| //----------------------------------------------------------------------------- | |
| // Sys_GetFactory <- module_t | |
| // Returns a pointer to createInterface_ft export | |
| //----------------------------------------------------------------------------- | |
| createInterface_ft Sys_GetFactory(module_t m) | |
| { | |
| if(!m) { | |
| return nullptr; | |
| } | |
| // todo: add the constnant | |
| return (createInterface_ft)Sys_GetProcAddress(m, "G_CreateInterface"); | |
| } | |
| //----------------------------------------------------------------------------- | |
| // Sys_GetFactory <- const char * | |
| // Returns a pointer to createInterface_ft export | |
| //----------------------------------------------------------------------------- | |
| createInterface_ft Sys_GetFactory(const char *filename) | |
| { | |
| // todo: add the constnant | |
| return (createInterface_ft)Sys_GetProcAddress(filename, "G_CreateInterface"); | |
| } | |
| //----------------------------------------------------------------------------- | |
| // Sys_GetFactoryThis | |
| // Returns a pointer to createInterface_ft from the current module | |
| //----------------------------------------------------------------------------- | |
| createInterface_ft Sys_GetFactoryThis(void) | |
| { | |
| return &CreateInterfaceInternal; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // this header declares system module loading functions | |
| // and the interface convention | |
| #ifndef INTERFACE_H | |
| #define INTERFACE_H | |
| // base class for all interfaces | |
| class IBaseInterface { | |
| public: | |
| virtual ~IBaseInterface(void) { /* ... */ } | |
| }; | |
| using createInterface_ft = IBaseInterface * (*)(const char *name); | |
| using instanceInterface_ft = IBaseInterface * (*)(void); | |
| // used to register interfaces | |
| class InterfaceReg { | |
| public: | |
| // global interface list | |
| static InterfaceReg * s_listHead; | |
| InterfaceReg * m_listNext; | |
| public: | |
| // interface data | |
| instanceInterface_ft m_instanceFn; | |
| const char * m_name; | |
| public: | |
| InterfaceReg(instanceInterface_ft instanceFn, const char *name); | |
| }; | |
| //----------------------------------------------------------------------------- | |
| // EXPOSE_INTERFACE | |
| // Creates a not-singleton interface | |
| //----------------------------------------------------------------------------- | |
| #define EXPOSE_INTERFACE(className, interfaceName, name) \ | |
| static IBaseInterface * s_Create##interfaceName##_fn(void) { return (interfaceName *)(new className); } \ | |
| static InterfaceReg s_##interfaceName##_reg(s_Create##interfaceName##_fn, name) | |
| //----------------------------------------------------------------------------- | |
| // EXPOSE_INTERFACE_SINGLE | |
| // Creates a singleton interface | |
| //----------------------------------------------------------------------------- | |
| #define EXPOSE_INTERFACE_SINGLE(className, interfaceName, name) \ | |
| static IBaseInterface * s_Instance##interfaceName##_fn(void) { static className s_impl; (interfaceName *)s_impl; } \ | |
| static InterfaceReg s_##interfaceName##_reg(s_Instance##interfaceName##_fn, name) | |
| // X.dll, X.so, X.dylib, X.etc | |
| using module_t = void *; | |
| // load/unload module functions | |
| module_t Sys_LoadModule(const char *filename); | |
| void Sys_UnloadModule(module_t m); | |
| // createinterface wrappers | |
| createInterface_ft Sys_GetFactory(module_t m); | |
| createInterface_ft Sys_GetFactory(const char *filename); | |
| createInterface_ft Sys_GetFactoryThis(void); | |
| // todo: CDllDemandLoader? | |
| #endif // !INTERFACE_H |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment