Skip to content

Instantly share code, notes, and snippets.

@untodesu
Last active January 19, 2020 12:02
Show Gist options
  • Save untodesu/79c87029318d2a03b9878788ed3c7515 to your computer and use it in GitHub Desktop.
Save untodesu/79c87029318d2a03b9878788ed3c7515 to your computer and use it in GitHub Desktop.
// 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 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