Interface changes: no more KIND ints, all context.name strings now;

Initial version of Event system


git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@1286 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
avolkov
2003-10-27 04:50:06 +00:00
parent a1656ce168
commit a6e4933338
8 changed files with 900 additions and 149 deletions
+115 -21
View File
@@ -26,6 +26,7 @@
#include "cdpint.h"
#include "cdpmod.h"
#include "uio.h"
#include "uqmversion.h"
#ifdef WIN32
# include "windl.h"
#else
@@ -35,10 +36,10 @@
#define MAX_CDPS 63
#define CDPDIR "cdps"
// internal adl module representation
// cdp_Module will be cast to and from this
// internal CDP module representation
struct cdp_Module
{
bool builtin; // used at least once indicator
bool used; // used at least once indicator
void* hmodule; // loaded module handle
uint32 refcount; // reference count
@@ -46,10 +47,39 @@ struct cdp_Module
};
// Kernel module info
// not a real module, and not loadable either
// this just provides information to other modules
cdp_ModuleInfo cdp_kernel_info =
{
sizeof (cdp_ModuleInfo),
CDPAPI_VERSION, // API version we are using
UQM_MAJOR_VERSION, UQM_MINOR_VERSION,
UQM_MAJOR_VERSION, UQM_MINOR_VERSION,
CDP_MODINFO_RESERVED1,
"UQM", // CDP context cannonical name
"UQM Kernel", // CDP mod name
# define S(i) #i
// CDP mod version
S(UQM_MAJOR_VERSION) "." S(UQM_MINOR_VERSION) UQM_EXTRA_VERSION,
# undef S
"UQM Team", // CDP mod author
"http://sc2.sf.net", // CDP mod URL
"Eternal doctrine executor", // CDP mod comment
CDP_MODINFO_RESERVED2,
NULL, NULL // no entrypoints defined/needed
};
static cdp_Module cdp_modules[MAX_CDPS + 1] =
{
{true, true, NULL, 1, &cdp_kernel_info},
{false, false, NULL, 0, NULL} // term
};
extern uio_DirHandle *cdpDir;
static bool cdp_inited = false;
static cdp_Module cdp_modules[MAX_CDPS + 1];
static cdp_Error cdp_last_error = CDPERR_NONE;
static char cdp_path[PATH_MAX] = "";
@@ -64,13 +94,25 @@ cdp_GetError (void)
bool
cdp_Init (void)
{
int i;
void* hkernel;
if (cdp_inited)
{
fprintf (stderr, "cdp_Init(): called when already inited\n");
return true;
}
memset (cdp_modules, 0, sizeof cdp_modules);
// preprocess built-in modules
hkernel = dlopen (NULL, RTLD_LAZY);
for (i = 0; cdp_modules[i].builtin; ++i)
cdp_modules[i].hmodule = hkernel;
// clear the rest
//memset (cdp_modules + i, 0,
// sizeof (cdp_modules) - sizeof (cdp_Module) * i);
//strcpy (cdp_path, cdpDir->path);
cdp_InitApi ();
cdp_inited = true;
@@ -94,6 +136,7 @@ cdp_Uninit (void)
cdp_Module*
cdp_LoadModule (const char* modname)
// special value for modname: NULL - refers to kernel (UQM exe)
{
void* mod;
char modpath[PATH_MAX];
@@ -104,6 +147,9 @@ cdp_LoadModule (const char* modname)
cdp_Module* newslot = 0;
cdp_Itf* ihost;
if (modname == NULL)
return cdp_modules;
if (!cdp_inited)
{
fprintf (stderr, "cdp_LoadModule(): called when not inited\n");
@@ -173,24 +219,33 @@ cdp_LoadModule (const char* modname)
return NULL;
}
if (!info->module_init ((cdp_Itf_Host*)ihost))
if (!newslot)
{
newslot = cdp;
newslot->used = true;
// make next one a term
cdp[1].builtin = false;
cdp[1].used = false;
cdp[1].hmodule = NULL;
cdp[1].refcount = 0;
}
newslot->hmodule = mod;
newslot->refcount = 1;
newslot->info = info;
if (!info->module_init (newslot, (cdp_Itf_Host*)ihost))
{
fprintf (stderr, "cdp_LoadModule(): "
"CDP %s failed to init\n",
modname);
dlclose (mod);
newslot->hmodule = NULL;
newslot->info = NULL;
newslot->refcount = 0;
cdp_last_error = CDPERR_INIT_FAILED;
return NULL;
}
if (!newslot)
{
newslot = cdp;
newslot->used = true;
}
newslot->hmodule = mod;
newslot->refcount = 1;
newslot->info = info;
return newslot;
}
@@ -210,7 +265,7 @@ cdp_FreeModule (cdp_Module* module)
{
cdp_Module* modslot = cdp_CheckModule (module);
if (!modslot)
if (!modslot || modslot->builtin)
return;
modslot->refcount--;
@@ -227,13 +282,38 @@ cdp_FreeModule (cdp_Module* module)
}
const char*
cdp_GetModuleName (cdp_Module* module)
cdp_GetModuleContext (cdp_Module* module, bool bMetaString)
{
cdp_Module* modslot = cdp_CheckModule (module);
if (bMetaString)
{
if (!modslot)
return "(Error)";
if (!modslot->info->context_name)
return "(Null)";
}
else if (!modslot)
{
return NULL;
}
return modslot->info->context_name;
}
const char*
cdp_GetModuleName (cdp_Module* module, bool bMetaString)
{
cdp_Module* modslot = cdp_CheckModule (module);
if (bMetaString)
{
if (!modslot)
return "(Error)";
if (!modslot->info->name)
return "(Null)";
}
else if (!modslot)
{
return NULL;
}
return modslot->info->name;
}
@@ -247,24 +327,38 @@ cdp_GetModuleVersion (cdp_Module* module)
}
const char*
cdp_GetModuleVersionString (cdp_Module* module)
cdp_GetModuleVersionString (cdp_Module* module, bool bMetaString)
{
cdp_Module* modslot = cdp_CheckModule (module);
if (bMetaString)
{
if (!modslot)
return "(Error)";
if (!modslot->info->ver_string)
return "(Null)";
}
else if (!modslot)
{
return NULL;
}
return modslot->info->ver_string;
}
const char*
cdp_GetModuleComment (cdp_Module* module)
cdp_GetModuleComment (cdp_Module* module, bool bMetaString)
{
cdp_Module* modslot = cdp_CheckModule (module);
if (bMetaString)
{
if (!modslot)
return "(Error)";
if (!modslot->info->comments)
return "(Null)";
}
else if (!modslot)
{
return NULL;
}
return modslot->info->comments;
}
@@ -309,9 +403,9 @@ cdp_LoadAllModules (void)
{
nummods++;
fprintf (stderr, "\tloaded CDP: %s v%s (%s)\n",
cdp_GetModuleName (mod),
cdp_GetModuleVersionString (mod),
cdp_GetModuleComment (mod));
cdp_GetModuleName (mod, true),
cdp_GetModuleVersionString (mod, true),
cdp_GetModuleComment (mod, true));
}
else
{
@@ -337,7 +431,7 @@ cdp_FreeAllModules (void)
for (cdp = cdp_modules; cdp->used; ++cdp)
{
if (cdp->hmodule)
if (!cdp->builtin && cdp->hmodule)
cdp_FreeModule (cdp);
}
}
+7 -3
View File
@@ -32,10 +32,14 @@ void cdp_Uninit (void);
cdp_Error cdp_GetError (void);
cdp_Module* cdp_LoadModule (const char* modname);
void cdp_FreeModule (cdp_Module* module);
const char* cdp_GetModuleName (cdp_Module* module);
// in the following calls when bMetaString is set
// function will never return a NULL, instead it will
// return a valid string -- error meta-string
const char* cdp_GetModuleContext (cdp_Module* module, bool bMetaString);
const char* cdp_GetModuleName (cdp_Module* module, bool bMetaString);
uint32 cdp_GetModuleVersion (cdp_Module* module);
const char* cdp_GetModuleVersionString (cdp_Module* module);
const char* cdp_GetModuleComment (cdp_Module* module);
const char* cdp_GetModuleVersionString (cdp_Module* module, bool bMetaString);
const char* cdp_GetModuleComment (cdp_Module* module, bool bMetaString);
int cdp_LoadAllModules (void);
void cdp_FreeAllModules (void);
+4 -2
View File
@@ -28,9 +28,11 @@
// CDP IO Interface entry points
typedef struct
{
uio_Stream* (* fopen) (uio_DirHandle *dir, const char *path, const char *mode);
uio_Stream* (* fopen) (uio_DirHandle *dir, const char *path,
const char *mode);
int (* fclose) (uio_Stream *stream);
size_t (* fread) (void *buf, size_t size, size_t nmemb, uio_Stream *stream);
size_t (* fread) (void *buf, size_t size, size_t nmemb,
uio_Stream *stream);
size_t (* fwrite) (const void *buf, size_t size, size_t nmemb,
uio_Stream *stream);
int (* fseek) (uio_Stream *stream, long offset, int whence);
+648 -69
View File
@@ -26,17 +26,32 @@
#include "uqmversion.h"
#define MAX_REG_ITFS 255
#define MAX_REG_EVENTS 1023
static cdp_Error cdp_api_error = CDPERR_NONE;
static uint32 cdp_Host_GetApiVersion (void);
static uint32 cdp_Host_GetVersion (void);
static cdp_Error cdp_Host_GetApiError (void);
static cdp_Itf* cdp_Host_GetItf (cdp_ItfKind);
static cdp_RegItf* cdp_Host_RegisterItf (cdp_ItfKind,
static cdp_Itf* cdp_Host_GetItf (const char* name);
static bool cdp_Host_GetItfs (cdp_ItfDef* defs);
static cdp_ItfReg* cdp_Host_RegisterItf (const char* name,
cdp_ApiVersion ver_from, cdp_ApiVersion ver_to,
cdp_Itf*, cdp_Module*);
static void cdp_Host_UnregisterItf (cdp_RegItf*);
static void cdp_Host_UnregisterItf (cdp_ItfReg*);
static bool cdp_Host_RegisterItfs (cdp_ItfDef* defs, cdp_Module*);
static void cdp_Host_UnregisterItfs (cdp_ItfDef* defs);
static cdp_Event cdp_Host_GetEvent (const char* name);
static bool cdp_Host_GetEvents (cdp_EventDef* defs);
static cdp_EventReg* cdp_Host_RegisterEvent (const char* name, cdp_Module*);
static void cdp_Host_UnregisterEvent (cdp_EventReg*);
static bool cdp_Host_RegisterEvents (cdp_EventDef* defs, cdp_Module*);
static void cdp_Host_UnregisterEvents (cdp_EventDef* defs);
static bool cdp_Host_SubscribeEvent (cdp_Event, cdp_EventProc, cdp_Module*);
static void cdp_Host_UnsubscribeEvent (cdp_Event, cdp_EventProc);
static bool cdp_Host_SubscribeEvents (cdp_EventDef* defs, cdp_Module*);
static void cdp_Host_UnsubscribeEvents (cdp_EventDef* defs);
static cdp_EventResult cdp_Host_FireEvent (cdp_EventReg*, uint32, void*);
// Interfaces
cdp_Itf_HostVtbl_v1 cdp_host_itf_v1 =
@@ -45,8 +60,22 @@ cdp_Itf_HostVtbl_v1 cdp_host_itf_v1 =
cdp_Host_GetVersion,
cdp_Host_GetApiError,
cdp_Host_GetItf,
cdp_Host_GetItfs,
cdp_Host_RegisterItf,
cdp_Host_UnregisterItf,
cdp_Host_RegisterItfs,
cdp_Host_UnregisterItfs,
cdp_Host_GetEvent,
cdp_Host_GetEvents,
cdp_Host_RegisterEvent,
cdp_Host_UnregisterEvent,
cdp_Host_RegisterEvents,
cdp_Host_UnregisterEvents,
cdp_Host_SubscribeEvent,
cdp_Host_UnsubscribeEvent,
cdp_Host_SubscribeEvents,
cdp_Host_UnsubscribeEvents,
cdp_Host_FireEvent,
};
cdp_Itf_MemoryVtbl_v1 cdp_memory_itf_v1 =
@@ -84,23 +113,24 @@ cdp_Itf_VideoVtbl_v1 cdp_video_itf_v1 =
VideoDecoder_Lookup,
};
struct cdp_RegItf
// the actual interface registration struct/handle
struct cdp_ItfReg
{
bool builtin;
bool used;
cdp_ItfKind kind;
const char* name;
cdp_ApiVersion ver_from;
cdp_ApiVersion ver_to;
cdp_Itf* itfvtbl;
cdp_Module* module;
};
#define CDP_DECLARE_ITF(k,vf,vt,vtbl) \
{true, true, CDPITF_KIND_##k, \
#define CDP_DECLARE_ITF(kind,vf,vt,vtbl) \
{true, true, CDPITF_KIND_##kind, \
CDPAPI_VERSION_##vf, CDPAPI_VERSION_##vt, vtbl, NULL}
// Built-in interfaces + space for loadable
cdp_RegItf cdp_itfs[MAX_REG_ITFS + 1] =
cdp_ItfReg cdp_itfs[MAX_REG_ITFS + 1] =
{
CDP_DECLARE_ITF (HOST, 1, 1, &cdp_host_itf_v1),
CDP_DECLARE_ITF (MEMORY, 1, 1, &cdp_memory_itf_v1),
@@ -109,7 +139,43 @@ cdp_RegItf cdp_itfs[MAX_REG_ITFS + 1] =
CDP_DECLARE_ITF (VIDEO, 1, 1, &cdp_video_itf_v1),
// TODO: put newly defined built-in interfaces here
{false, false, CDPITF_KIND_INVALID, 0, 0, NULL} // term
{false, false, "", 0, 0, NULL} // term
};
// event bind descriptor
typedef struct
{
cdp_EventProc proc;
cdp_Module* module;
} cdp_EventBind;
#define EVENT_BIND_GROW 16
// the actual event registration struct/handle
struct cdp_EventReg
{
bool builtin;
bool used;
const char* name;
cdp_EventBind* binds;
uint32 bindslots;
cdp_Module* module;
};
#define CDP_DECLARE_EVENT(name) \
{true, true, "UQM." #name, NULL, 0, NULL}
// Built-in events + space for loadable
// a cdp_Event handle is an index into this array
cdp_EventReg cdp_evts[MAX_REG_EVENTS + 1] =
{
// sample - no real events defined yet
CDP_DECLARE_EVENT (PlanetSide.TouchDown),
CDP_DECLARE_EVENT (PlanetSide.LiftOff),
// TODO: put newly defined built-in events here
{false, false, "", NULL, 0, NULL} // term
};
cdp_Error
@@ -123,14 +189,34 @@ cdp_GetApiError (void)
bool
cdp_InitApi (void)
{
// TODO: add whatever init code is necessary
int i;
cdp_Module* kernel;
// preprocess built-in itfs
kernel = cdp_LoadModule (NULL);
for (i = 0; cdp_itfs[i].builtin; ++i)
{
cdp_itfs[i].module = kernel;
}
// clear the rest
//memset (cdp_itfs + i, 0,
// sizeof (cdp_itfs) - sizeof (cdp_ItfReg) * i);
for (i = 0; cdp_evts[i].builtin; ++i)
{
cdp_evts[i].module = kernel;
cdp_evts[i].bindslots = 0;
cdp_evts[i].binds = NULL;
}
return true;
}
void
cdp_UninitApi (void)
{
cdp_RegItf* itf;
cdp_ItfReg* itf;
// unregister custom interfaces
for (itf = cdp_itfs; itf->used; ++itf)
@@ -138,31 +224,15 @@ cdp_UninitApi (void)
if (!itf->builtin)
{
itf->used = false;
itf->kind = CDPITF_KIND_INVALID;
if (itf->name)
HFree ((void*) itf->name);
itf->name = NULL;
itf->itfvtbl = NULL;
itf->module = NULL;
}
}
}
cdp_Itf*
cdp_GetInterface (cdp_ItfKind itf_kind, cdp_ApiVersion api_ver)
{
cdp_RegItf* itf;
for (itf = cdp_itfs; itf->used &&
(itf->kind != itf_kind ||
api_ver < itf->ver_from || api_ver > itf->ver_to);
itf++)
;
if (!itf->kind)
{
cdp_api_error = CDPERR_NO_ITF;
return NULL;
}
return itf->itfvtbl;
}
static uint32
cdp_Host_GetApiVersion (void)
{
@@ -181,32 +251,125 @@ cdp_Host_GetApiError (void)
return cdp_GetApiError ();
}
static cdp_Itf*
cdp_Host_GetItf (cdp_ItfKind itf_kind)
static char*
cdp_MakeContextName (const char* ctx, const char* name)
{
return cdp_GetInterface (itf_kind, CDPAPI_VERSION_1);
int namelen;
char* id_name;
namelen = strlen(ctx) + strlen(name) + 2;
id_name = HMalloc (namelen);
strcpy(id_name, ctx);
strcat(id_name, ".");
strcat(id_name, name);
return id_name;
}
static cdp_RegItf*
cdp_Host_RegisterItf (cdp_ItfKind itf_kind, cdp_ApiVersion ver_from,
cdp_ApiVersion ver_to, cdp_Itf* itfvtbl, cdp_Module* module)
{
cdp_RegItf* regitf;
cdp_RegItf* newslot = NULL;
/***********************************************************
* Interface system *
***********************************************************/
if (!module)
cdp_ItfReg*
cdp_GetInterfaceReg (const char* name, cdp_ApiVersion api_ver)
{
cdp_ItfReg* itf;
for (itf = cdp_itfs; itf->used &&
(!itf->name || stricmp(itf->name, name) != 0 ||
api_ver < itf->ver_from || api_ver > itf->ver_to);
itf++)
;
if (!itf->name)
{
cdp_api_error = CDPERR_NO_ITF;
return NULL;
}
return itf;
}
cdp_Itf*
cdp_GetInterface (const char* name, cdp_ApiVersion api_ver)
{
cdp_ItfReg* reg;
reg = cdp_GetInterfaceReg (name, api_ver);
return reg ? reg->itfvtbl : NULL;
}
static cdp_Itf*
cdp_Host_GetItf (const char* name)
{
return cdp_GetInterface (name, CDPAPI_VERSION_1);
}
static bool
cdp_Host_GetItfs (cdp_ItfDef* defs)
{
cdp_ItfDef* def;
cdp_ItfReg* reg;
int errors = 0;
for (def = defs; def->name; ++def)
{
// registration handle is not returned
def->reg = NULL;
reg = cdp_GetInterfaceReg (def->name, CDPAPI_VERSION_1);
if (reg)
{
def->itf = reg->itfvtbl;
def->name = reg->name; // set to cannonical name
def->ver_from = reg->ver_from;
def->ver_to = reg->ver_to;
def->module = reg->module;
}
else
{
def->itf = NULL;
def->module = NULL;
def->ver_from = 0;
def->ver_to = 0;
++errors;
}
}
return !errors;
}
static cdp_ItfReg*
cdp_Host_RegisterItf (const char* name, cdp_ApiVersion ver_from,
cdp_ApiVersion ver_to, cdp_Itf* itfvtbl,
cdp_Module* owner)
{
cdp_ItfReg* itfreg;
cdp_ItfReg* newslot = NULL;
char* id_name;
const char* ctx;
if (!owner)
{
fprintf (stderr, "cdp_Host_RegisterItf(): "
"No module info supplied\n");
"No owner info supplied\n");
//return NULL;
}
if (!itf_kind || !itfvtbl)
if (!name || !*name || !itfvtbl)
{
fprintf (stderr, "cdp_Host_RegisterItf(): "
"Null or invalid interface (from %s)\n",
cdp_GetModuleName (module));
cdp_GetModuleName (owner, true));
return NULL;
}
ctx = cdp_GetModuleContext (owner, false);
if (!ctx)
{
fprintf (stderr, "cdp_Host_RegisterItf(): "
"Null or invalid context (from %s)\n",
cdp_GetModuleName (owner, true));
return NULL;
}
// TODO: review version policy (below)
// enforce version policy and do not allow obsolete interfaces
// POLICY: all modules MUST be aware of recent API changes and will not
@@ -217,68 +380,484 @@ cdp_Host_RegisterItf (cdp_ItfKind itf_kind, cdp_ApiVersion ver_from,
if (ver_to < CDPAPI_VERSION_MIN)
{
fprintf (stderr, "cdp_Host_RegisterItf(): "
"Obsolete interface 0x%08x (from %s)\n",
itf_kind, cdp_GetModuleName (module));
"Obsolete interface %s (from %s)\n",
name, cdp_GetModuleName (owner, true));
return NULL;
}
// check if extension already registered
for (regitf = cdp_itfs; regitf->used &&
(regitf->kind != itf_kind ||
ver_from < regitf->ver_from || ver_to > regitf->ver_to);
++regitf)
id_name = cdp_MakeContextName (ctx, name);
// check if interface already registered
for (itfreg = cdp_itfs; itfreg->used &&
(!itfreg->name || stricmp(itfreg->name, id_name) != 0 ||
ver_from < itfreg->ver_from || ver_to > itfreg->ver_to);
++itfreg)
{
// and pick up an empty slot (where available)
if (!newslot && !regitf->kind)
newslot = regitf;
if (!newslot && !itfreg->name)
newslot = itfreg;
}
if (regitf >= cdp_itfs + MAX_REG_ITFS)
if (itfreg >= cdp_itfs + MAX_REG_ITFS)
{
fprintf (stderr, "cdp_Host_RegisterItf(): "
"Interfaces limit reached\n");
HFree (id_name);
return NULL;
}
else if (regitf->kind)
else if (itfreg->name)
{
fprintf (stderr, "cdp_Host_RegisterItf(): "
"interface 0x%08x already registered for these versions, "
"Interface %s already registered for these versions, "
"%s denied\n",
itf_kind, cdp_GetModuleName (module));
name, cdp_GetModuleName (owner, true));
HFree (id_name);
return NULL;
}
if (!newslot)
{
newslot = regitf;
newslot = itfreg;
newslot->used = true;
// make next one a term
regitf[1].builtin = false;
regitf[1].used = false;
regitf[1].kind = CDPITF_KIND_INVALID;
regitf[1].itfvtbl = NULL;
itfreg[1].builtin = false;
itfreg[1].used = false;
itfreg[1].name = NULL;
itfreg[1].itfvtbl = NULL;
}
newslot->kind = itf_kind;
newslot->name = id_name;
newslot->ver_from = ver_from;
newslot->ver_to = ver_to;
newslot->itfvtbl = itfvtbl;
newslot->module = module;
newslot->module = owner;
return newslot;
}
static void
cdp_Host_UnregisterItf (cdp_RegItf* regitf)
cdp_Host_UnregisterItf (cdp_ItfReg* itfreg)
{
if (regitf < cdp_itfs || regitf >= cdp_itfs + MAX_REG_ITFS ||
!regitf->kind || !regitf->itfvtbl)
if (itfreg < cdp_itfs || itfreg >= cdp_itfs + MAX_REG_ITFS ||
!itfreg->name || !itfreg->itfvtbl)
{
fprintf (stderr, "cdp_Host_UnregisterItf(): "
"Invalid or expired interface passed\n");
return;
}
regitf->kind = CDPITF_KIND_INVALID;
regitf->itfvtbl = NULL;
if (!itfreg->builtin)
{
HFree ((void*) itfreg->name);
}
itfreg->module = NULL;
itfreg->name = NULL;
itfreg->itfvtbl = NULL;
}
static bool
cdp_Host_RegisterItfs (cdp_ItfDef* defs, cdp_Module* owner)
{
cdp_ItfDef* def;
int errors = 0;
for (def = defs; def->name; ++def)
{
def->reg = cdp_Host_RegisterItf (def->name, def->ver_from,
def->ver_to, def->itf, owner);
if (def->reg)
{
def->module = owner;
}
else
{
def->module = NULL;
++errors;
}
}
return !errors;
}
static void
cdp_Host_UnregisterItfs (cdp_ItfDef* defs)
{
cdp_ItfDef* def;
for (def = defs; def->name; ++def)
{
if (def->reg)
cdp_Host_UnregisterItf (def->reg);
}
}
/***********************************************************
* Event system *
***********************************************************/
cdp_EventReg*
cdp_GetEventReg (const char* name)
{
cdp_EventReg* evt;
for (evt = cdp_evts; evt->used &&
(!evt->name || stricmp(evt->name, name) != 0);
evt++)
;
if (!evt->name)
{
cdp_api_error = CDPERR_NO_EVENT;
return NULL;
}
return evt;
}
// hopefully inlinable
static cdp_Event
cdp_EventFromReg (cdp_EventReg* reg)
{
return (reg - cdp_evts) / sizeof (cdp_EventReg);
}
// hopefully inlinable
static cdp_EventReg*
cdp_RegFromEvent (cdp_Event event)
{
return cdp_evts + event;
}
cdp_Event
cdp_GetEvent (const char* name)
{
cdp_EventReg* reg;
reg = cdp_GetEventReg (name);
return reg ? cdp_EventFromReg (reg) : CDP_EVENT_INVALID;
}
static cdp_EventBind*
cdp_AllocEventBinds (cdp_EventBind* binds, uint32 ccur, uint32 cnew)
{
cdp_EventBind* newbinds;
uint32 newsize;
newsize = cnew * sizeof (cdp_EventBind);
if (binds)
newbinds = HRealloc (binds, newsize);
else
newbinds = HMalloc (newsize);
if (cnew > ccur)
memset (newbinds + ccur, 0,
(cnew - ccur) * sizeof (cdp_EventBind));
return newbinds;
}
static cdp_Event
cdp_Host_GetEvent (const char* name)
{
return cdp_GetEvent (name);
}
static bool
cdp_Host_GetEvents (cdp_EventDef* defs)
{
cdp_EventDef* def;
cdp_EventReg* reg;
int errors = 0;
for (def = defs; def->name; ++def)
{
// registration handle is not returned
def->reg = NULL;
reg = cdp_GetEventReg (def->name);
if (reg)
{
def->event = cdp_EventFromReg(reg);
def->name = reg->name; // set to cannonical name
def->module = reg->module;
}
else
{
def->event = CDP_EVENT_INVALID;
def->module = NULL;
++errors;
}
}
return !errors;
}
static cdp_EventReg*
cdp_Host_RegisterEvent (const char* name, cdp_Module* owner)
{
cdp_EventReg* evtreg;
cdp_EventReg* newslot = NULL;
char* id_name;
const char* ctx;
if (!owner)
{
fprintf (stderr, "cdp_Host_RegisterEvent(): "
"No owner info supplied\n");
//return NULL;
}
if (!name || !*name)
{
fprintf (stderr, "cdp_Host_RegisterEvent(): "
"Null or invalid event (from %s)\n",
cdp_GetModuleName (owner, true));
return NULL;
}
ctx = cdp_GetModuleContext (owner, false);
if (!ctx)
{
fprintf (stderr, "cdp_Host_RegisterEvent(): "
"Null or invalid context (from %s)\n",
cdp_GetModuleName (owner, true));
return NULL;
}
id_name = cdp_MakeContextName (ctx, name);
// check if event already registered
for (evtreg = cdp_evts; evtreg->used &&
(!evtreg->name || stricmp(evtreg->name, id_name) != 0);
++evtreg)
{
// and pick up an empty slot (where available)
if (!newslot && !evtreg->name)
newslot = evtreg;
}
if (evtreg >= cdp_evts + MAX_REG_EVENTS)
{
fprintf (stderr, "cdp_Host_RegisterEvent(): "
"Event limit reached\n");
HFree (id_name);
return NULL;
}
else if (evtreg->name)
{
fprintf (stderr, "cdp_Host_RegisterEvent(): "
"Event %s already registered, "
"%s denied\n",
name, cdp_GetModuleName (owner, true));
HFree (id_name);
return NULL;
}
if (!newslot)
{
newslot = evtreg;
newslot->used = true;
// make next one a term
evtreg[1].builtin = false;
evtreg[1].used = false;
evtreg[1].name = NULL;
}
newslot->name = id_name;
newslot->module = owner;
newslot->binds = NULL;
newslot->bindslots = 0;
return newslot;
}
static void
cdp_Host_UnregisterEvent (cdp_EventReg* evtreg)
{
if (evtreg < cdp_evts || evtreg >= cdp_evts + MAX_REG_EVENTS ||
!evtreg->name)
{
fprintf (stderr, "cdp_Host_UnregisterEvent(): "
"Invalid or expired event passed\n");
return;
}
if (!evtreg->builtin)
{
HFree ((void*) evtreg->name);
}
evtreg->module = NULL;
evtreg->name = NULL;
if (evtreg->binds)
HFree (evtreg->binds);
evtreg->binds = NULL;
evtreg->bindslots = 0;
}
static bool
cdp_Host_RegisterEvents (cdp_EventDef* defs, cdp_Module* owner)
{
cdp_EventDef* def;
int errors = 0;
for (def = defs; def->name; ++def)
{
def->reg = cdp_Host_RegisterEvent (def->name, owner);
if (def->reg)
{
def->module = owner;
}
else
{
def->module = NULL;
++errors;
}
}
return !errors;
}
static void
cdp_Host_UnregisterEvents (cdp_EventDef* defs)
{
cdp_EventDef* def;
for (def = defs; def->name; ++def)
{
if (def->reg)
cdp_Host_UnregisterEvent (def->reg);
}
}
static bool
cdp_Host_SubscribeEvent (cdp_Event event, cdp_EventProc proc, cdp_Module* module)
{
cdp_EventReg* reg = cdp_RegFromEvent (event);
cdp_EventBind* bind = NULL;
uint32 i;
if (reg < cdp_evts || reg >= cdp_evts + MAX_REG_EVENTS ||
!reg->name)
{
fprintf (stderr, "cdp_Host_SubscribeEvent(): "
"Invalid or expired event passed\n");
return false;
}
if (reg->binds)
{
// check for duplicate or find a new slot
for (i = 0, bind = reg->binds; i < reg->bindslots &&
(!bind->proc || bind->proc != proc);
++i, ++bind)
;
if (i >= reg->bindslots)
{ // full - add more slots
reg->binds = cdp_AllocEventBinds (reg->binds,
reg->bindslots, reg->bindslots + EVENT_BIND_GROW);
bind = reg->binds + reg->bindslots;
reg->bindslots += EVENT_BIND_GROW;
}
else if (bind->proc == proc)
{ // already bound
return true;
}
}
else
{
reg->binds = cdp_AllocEventBinds (NULL, 0, EVENT_BIND_GROW);
reg->bindslots = EVENT_BIND_GROW;
bind = reg->binds;
}
bind->proc = proc;
bind->module = module;
return true;
}
static void
cdp_Host_UnsubscribeEvent (cdp_Event event, cdp_EventProc proc)
{
cdp_EventReg* reg = cdp_RegFromEvent (event);
cdp_EventBind* bind = NULL;
uint32 i;
if (reg < cdp_evts || reg >= cdp_evts + MAX_REG_EVENTS ||
!reg->name)
{ // event either expired or invalid
return;
}
if (!reg->binds || !reg->bindslots)
return; // hmm, no bindings
// check for duplicate or find a new slot
for (i = 0, bind = reg->binds; i < reg->bindslots &&
bind->proc != proc;
++i, ++bind)
;
if (i >= reg->bindslots)
return; // binding not found
bind->proc = NULL;
bind->module = NULL;
}
static bool
cdp_Host_SubscribeEvents (cdp_EventDef* defs, cdp_Module* module)
{
cdp_EventDef* def;
int errors = 0;
for (def = defs; def->name; ++def)
{
if (def->event != CDP_EVENT_INVALID && def->proc)
if (!cdp_Host_SubscribeEvent (def->event, def->proc, module))
++errors;
}
return !errors;
}
static void
cdp_Host_UnsubscribeEvents (cdp_EventDef* defs)
{
cdp_EventDef* def;
for (def = defs; def->name; ++def)
{
if (def->event != CDP_EVENT_INVALID && def->proc)
cdp_Host_UnsubscribeEvent (def->event, def->proc);
}
}
static cdp_EventResult
cdp_Host_FireEvent (cdp_EventReg* evtreg, uint32 iparam, void* pparam)
{
bool bHandled = false;
cdp_EventResult ret = 0;
cdp_Event event;
cdp_EventBind* bind;
uint32 i;
if (evtreg < cdp_evts || evtreg >= cdp_evts + MAX_REG_EVENTS ||
!evtreg->name)
{
#ifdef DEBUG
fprintf (stderr, "cdp_Host_FireEvent(): Invalid event\n");
#endif
return 0;
}
if (!evtreg->binds)
return 0; // no subscribers
event = cdp_EventFromReg (evtreg);
// call event procs in opposite order of binding
for (i = evtreg->bindslots, bind = evtreg->binds + i - 1;
!bHandled && i > 0;
--i, --bind)
{
if (bind->proc)
ret = bind->proc (event, iparam, pparam, &bHandled);
}
return ret;
}
+77 -23
View File
@@ -46,36 +46,76 @@ typedef enum
CDPERR_INIT_FAILED = 7,
CDPERR_NO_ITF = 8,
CDPERR_DUPE_ITF = 9,
CDPERR_NO_EVENT = 10,
CDPERR_DUPE_EVENT = 11,
CDPERR_OTHER = 1000,
} cdp_Error;
typedef struct cdp_Module cdp_Module;
typedef void cdp_Itf;
typedef struct cdp_RegItf cdp_RegItf;
typedef struct cdp_ItfReg cdp_ItfReg;
typedef enum
// Interface KINDs - for convinience and uniformity
#define CDPITF_KIND_INVALID NULL
#define CDPITF_KIND_HOST "UQM.Host"
#define CDPITF_KIND_MEMORY "UQM.Memory"
#define CDPITF_KIND_IO "UQM.IO"
#define CDPITF_KIND_THREADS "UQM.Threads"
#define CDPITF_KIND_TIME "UQM.Time"
#define CDPITF_KIND_INPUT "UQM.Input"
#define CDPITF_KIND_TASK "UQM.Task"
#define CDPITF_KIND_RESOURCE "UQM.Resource"
#define CDPITF_KIND_SOUND "UQM.Sound"
#define CDPITF_KIND_VIDEO "UQM.Video"
#define CDPITF_KIND_GFX "UQM.Gfx"
#define CDPITF_KIND_MIXER "UQM.Mixer"
// Interface definition structure
// pass an array of these to Host->GetItfs() for batch lookup
// pass an array of these to Host->RegisterItfs() for batch registration
typedef struct
{
CDPITF_KIND_INVALID = 0,
CDPITF_KIND_HOST = 1,
CDPITF_KIND_MEMORY = 2,
CDPITF_KIND_IO = 3,
CDPITF_KIND_THREADS = 4,
CDPITF_KIND_TIME = 5,
CDPITF_KIND_INPUT = 6,
CDPITF_KIND_TASK = 7,
CDPITF_KIND_RESOURCE = 8,
CDPITF_KIND_SOUND = 9,
CDPITF_KIND_VIDEO = 10,
CDPITF_KIND_GFX = 11,
CDPITF_KIND_MIXER = 12,
// anything up to 65536 is reserved
// apply for your KIND (range) officially in UQM bugzilla (for now)
// fill in the first 4 members for batch registration
// fill in the 1st member for batch lookup
// terminate an array of these defs with name == NULL
const char* name; // interface ID
cdp_Itf* itf; // interface pointer
cdp_ApiVersion ver_from; // lowest supported version
cdp_ApiVersion ver_to; // highest supported version
// custom interfaces live here
# include "cdpitfs.h"
cdp_Module* module; // owner module
// the following member is only set during registration
cdp_ItfReg* reg; // registration handle (not set on lookup)
} cdp_ItfKind;
} cdp_ItfDef;
typedef unsigned int cdp_Event;
typedef struct cdp_EventReg cdp_EventReg;
typedef intptr_t cdp_EventResult;
#define CDP_EVENT_INVALID (-1)
// used with cdp_Event
typedef cdp_EventResult (* cdp_EventProc)
(cdp_Event, uint32, void*, bool* pbHandled);
// Event definition structure
// pass an array of these to Host->GetItfs() for batch lookup
typedef struct
{
// fill in the 1st member for batch lookup or registration
// also fill in the 2nd member for batch subscription
// terminate an array of these defs with name == NULL
const char* name; // event ID
cdp_EventProc proc; // event proc, set to NULL for no bind
cdp_Event event; // subscribable event handle
cdp_Module* module; // owner module
// the following member is only set during registration
cdp_EventReg* reg; // registration handle (not set on lookup)
} cdp_EventDef;
// Host Interface
// the main itf of the API, it is passed to a loaded module
@@ -86,11 +126,25 @@ typedef struct
uint32 (* GetApiVersion) (void);
uint32 (* GetVersion) (void);
cdp_Error (* GetApiError) (void);
cdp_Itf* (* GetItf) (cdp_ItfKind);
cdp_RegItf* (* RegisterItf) (cdp_ItfKind,
cdp_Itf* (* GetItf) (const char* name);
bool (* GetItfs) (cdp_ItfDef* defs);
cdp_ItfReg* (* RegisterItf) (const char* name,
cdp_ApiVersion ver_from, cdp_ApiVersion ver_to,
cdp_Itf*, cdp_Module*);
void (* UnregisterItf) (cdp_RegItf*);
void (* UnregisterItf) (cdp_ItfReg*);
bool (* RegisterItfs) (cdp_ItfDef* defs, cdp_Module*);
void (* UnregisterItfs) (cdp_ItfDef* defs);
cdp_Event (* GetEvent) (const char* name);
bool (* GetEvents) (cdp_EventDef* defs);
cdp_EventReg* (* RegisterEvent) (const char* name, cdp_Module*);
void (* UnregisterEvent) (cdp_EventReg*);
bool (* RegisterEvents) (cdp_EventDef* defs, cdp_Module*);
void (* UnregisterEvents) (cdp_EventDef* defs);
bool (* SubscribeEvent) (cdp_Event, cdp_EventProc, cdp_Module*);
void (* UnsubscribeEvent) (cdp_Event, cdp_EventProc);
bool (* SubscribeEvents) (cdp_EventDef* defs, cdp_Module*);
void (* UnsubscribeEvents) (cdp_EventDef* defs);
cdp_EventResult (* FireEvent) (cdp_EventReg*, uint32, void*);
} cdp_Itf_HostVtbl_v1;
+2 -1
View File
@@ -42,6 +42,7 @@ extern cdp_Itf_SoundVtbl_v1 cdp_sound_itf_v1;
bool cdp_InitApi (void);
void cdp_UninitApi (void);
cdp_Error cdp_GetApiError (void);
cdp_Itf* cdp_GetInterface (cdp_ItfKind itf_kind, cdp_ApiVersion api_ver);
cdp_Itf* cdp_GetInterface (const char* name, cdp_ApiVersion);
cdp_ItfReg* cdp_GetInterfaceReg (const char* name, cdp_ApiVersion);
#endif /* _CDPISND_H */
+25 -12
View File
@@ -41,27 +41,40 @@ typedef struct
uint16 host_ver_major; // minimum host version required, purely informational
uint16 host_ver_minor;
uint32 _32_reserved1[4]; // reserved members: set to all 0s or CDP_MODINFO_RESERVED1
// reserved members: set all to 0 or use CDP_MODINFO_RESERVED1
uint32 _32_reserved1;
uint32 _32_reserved2;
uint32 _32_reserved3;
uint32 _32_reserved4;
// informational, human-only
const char* name;
const char* ver_string;
const char* author;
const char* url;
const char* comments;
const char* context_name;
// cannonical context name (in proper case)
// this context will be used with all exposed objects
// English preferred; try to keep it below 32 chars
// informational, human-only; these fields have no real size
// restriction other than to keep it reasonable
const char* name; // descriptive name
const char* ver_string; // descriptive version
const char* author; // go nuts
const char* url; // go nuts
const char* comments; // go nuts
const char* _sz_reserved2[5]; // reserved members, set to all 0s or CDP_MODINFO_RESERVED2
// reserved members, set all to 0 or use CDP_MODINFO_RESERVED2
const char* _sz_reserved1;
const char* _sz_reserved2;
const char* _sz_reserved3;
const char* _sz_reserved4;
// mandatory, CDP entry points
// TODO: decide whether more EPs are necessary and if not move
// EPs above info-string members, abolishing _sz_reserved2
bool (* module_init) (cdp_Itf_Host* hostitf);
// EPs above info-string members, abolishing _sz_reservedX
bool (* module_init) (cdp_Module* module, cdp_Itf_Host* hostitf);
void (* module_term) ();
} cdp_ModuleInfo;
#define CDP_MODINFO_RESERVED1 {0,0,0,0}
#define CDP_MODINFO_RESERVED2 {0,0,0,0,0}
#define CDP_MODINFO_RESERVED1 0,0,0,0
#define CDP_MODINFO_RESERVED2 0,0,0,0
// the following is defined via the last mandatory member
#define CDP_MODINFO_MIN_SIZE \
+4
View File
@@ -36,7 +36,11 @@ dlopen (const char *filename, int flag)
{
HMODULE hlib;
if (filename == NULL)
hlib = GetModuleHandleA(NULL);
else
hlib = LoadLibraryA (filename);
if (!hlib)
wdl_last_error = GetLastError ();