diff --git a/sc2/src/sc2code/libs/cdp/cdp.c b/sc2/src/sc2code/libs/cdp/cdp.c index c08d70a8e..acbec9f90 100644 --- a/sc2/src/sc2code/libs/cdp/cdp.c +++ b/sc2/src/sc2code/libs/cdp/cdp.c @@ -26,6 +26,7 @@ #include "cdpint.h" #include "cdpmod.h" #include "uio.h" +#include "uqmversion.h" #ifdef WIN32 # include "windl.h" #else @@ -35,21 +36,50 @@ #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 used; // used at least once indicator - void* hmodule; // loaded module handle - uint32 refcount; // reference count + bool builtin; // used at least once indicator + bool used; // used at least once indicator + void* hmodule; // loaded module handle + uint32 refcount; // reference count cdp_ModuleInfo* info; // cdp exported info }; +// 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 (!modslot) - return "(Error)"; - if (!modslot->info->name) - return "(Null)"; + 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 (!modslot) - return "(Error)"; - if (!modslot->info->ver_string) - return "(Null)"; + 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 (!modslot) - return "(Error)"; - if (!modslot->info->comments) - return "(Null)"; + 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); } } diff --git a/sc2/src/sc2code/libs/cdp/cdp.h b/sc2/src/sc2code/libs/cdp/cdp.h index 39e991f9f..a8a7f5981 100644 --- a/sc2/src/sc2code/libs/cdp/cdp.h +++ b/sc2/src/sc2code/libs/cdp/cdp.h @@ -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); diff --git a/sc2/src/sc2code/libs/cdp/cdp_iio.h b/sc2/src/sc2code/libs/cdp/cdp_iio.h index 461af7e53..1fd999577 100644 --- a/sc2/src/sc2code/libs/cdp/cdp_iio.h +++ b/sc2/src/sc2code/libs/cdp/cdp_iio.h @@ -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); diff --git a/sc2/src/sc2code/libs/cdp/cdpapi.c b/sc2/src/sc2code/libs/cdp/cdpapi.c index 5b6822119..31a743cc3 100644 --- a/sc2/src/sc2code/libs/cdp/cdpapi.c +++ b/sc2/src/sc2code/libs/cdp/cdpapi.c @@ -25,18 +25,33 @@ #include "cdpint.h" #include "uqmversion.h" -#define MAX_REG_ITFS 255 +#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; } + + 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; + } - regitf->kind = CDPITF_KIND_INVALID; - regitf->itfvtbl = 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; } diff --git a/sc2/src/sc2code/libs/cdp/cdpapi.h b/sc2/src/sc2code/libs/cdp/cdpapi.h index f50c57dec..e0641e4b5 100644 --- a/sc2/src/sc2code/libs/cdp/cdpapi.h +++ b/sc2/src/sc2code/libs/cdp/cdpapi.h @@ -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; diff --git a/sc2/src/sc2code/libs/cdp/cdpint.h b/sc2/src/sc2code/libs/cdp/cdpint.h index 340af6f6c..9616af9e8 100644 --- a/sc2/src/sc2code/libs/cdp/cdpint.h +++ b/sc2/src/sc2code/libs/cdp/cdpint.h @@ -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 */ diff --git a/sc2/src/sc2code/libs/cdp/cdpmod.h b/sc2/src/sc2code/libs/cdp/cdpmod.h index da4f160e1..78a62c5e5 100644 --- a/sc2/src/sc2code/libs/cdp/cdpmod.h +++ b/sc2/src/sc2code/libs/cdp/cdpmod.h @@ -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 \ diff --git a/sc2/src/sc2code/libs/cdp/windl.c b/sc2/src/sc2code/libs/cdp/windl.c index e2cd6a139..4bc76f6ff 100644 --- a/sc2/src/sc2code/libs/cdp/windl.c +++ b/sc2/src/sc2code/libs/cdp/windl.c @@ -36,7 +36,11 @@ dlopen (const char *filename, int flag) { HMODULE hlib; - hlib = LoadLibraryA (filename); + if (filename == NULL) + hlib = GetModuleHandleA(NULL); + else + hlib = LoadLibraryA (filename); + if (!hlib) wdl_last_error = GetLastError ();