dvander@173: #include dvander@173: #include "PluginSys.h" dvander@190: #include "LibrarySys.h" dvander@173: dvander@174: CPluginManager g_PluginMngr; dvander@174: dvander@174: CPluginManager::CPluginManager() dvander@174: { dvander@174: } dvander@173: dvander@173: CPlugin *CPlugin::CreatePlugin(const char *file, dvander@173: bool debug_default, dvander@174: PluginType type, dvander@173: char *error, dvander@173: size_t maxlen) dvander@173: { dvander@173: static unsigned int MySerial = 0; dvander@173: FILE *fp = fopen(file, "rb"); dvander@173: dvander@173: if (!fp) dvander@173: { dvander@173: snprintf(error, maxlen, "Could not open file"); dvander@173: return NULL; dvander@173: } dvander@173: dvander@173: int err; dvander@173: sp_plugin_t *pl = g_pSourcePawn->LoadFromFilePointer(fp, &err); dvander@173: if (pl == NULL) dvander@173: { dvander@173: snprintf(error, maxlen, "Could not load plugin, error %d", err); dvander@173: return NULL; dvander@173: } dvander@173: dvander@173: fclose(fp); dvander@173: dvander@173: ICompilation *co = g_pVM->StartCompilation(pl); dvander@173: dvander@173: if (debug_default) dvander@173: { dvander@173: if (!g_pVM->SetCompilationOption(co, "debug", "1")) dvander@173: { dvander@173: g_pVM->AbortCompilation(co); dvander@173: snprintf(error, maxlen, "Could not set plugin to debug mode"); dvander@173: return NULL; dvander@173: } dvander@173: } dvander@173: dvander@173: sp_context_t *ctx = g_pVM->CompileToContext(co, &err); dvander@173: if (ctx == NULL) dvander@173: { dvander@173: snprintf(error, maxlen, "Plugin failed to load, JIT error: %d", err); dvander@173: return NULL; dvander@173: } dvander@173: dvander@173: IPluginContext *base = g_pSourcePawn->CreateBaseContext(ctx); dvander@173: CPlugin *pPlugin = new CPlugin; dvander@173: dvander@173: snprintf(pPlugin->m_filename, PLATFORM_MAX_PATH, "%s", file); dvander@173: pPlugin->m_debugging = debug_default; dvander@173: pPlugin->m_ctx_current.base = base; dvander@173: pPlugin->m_ctx_current.ctx = ctx; dvander@174: pPlugin->m_type = type; dvander@173: pPlugin->m_serial = ++MySerial; dvander@173: pPlugin->m_status = Plugin_Loaded; dvander@173: pPlugin->m_plugin = pl; dvander@173: dvander@173: pPlugin->UpdateInfo(); dvander@173: dvander@174: ctx->user[SM_CONTEXTVAR_MYSELF] = (void *)(IPlugin *)pPlugin; dvander@174: dvander@176: /* Build function information loosely */ dvander@176: pPlugin->m_funcsnum = g_pVM->FunctionCount(ctx); dvander@176: dvander@176: if (pPlugin->m_funcsnum) dvander@176: { dvander@176: pPlugin->m_priv_funcs = new CFunction *[pPlugin->m_funcsnum]; dvander@176: memset(pPlugin->m_priv_funcs, 0, sizeof(CFunction *) * pPlugin->m_funcsnum); dvander@176: } else { dvander@176: pPlugin->m_priv_funcs = NULL; dvander@176: } dvander@176: dvander@176: if (pl->info.publics_num) dvander@176: { dvander@176: pPlugin->m_pub_funcs = new CFunction *[pl->info.publics_num]; dvander@176: memset(pPlugin->m_pub_funcs, 0, sizeof(CFunction *) * pl->info.publics_num); dvander@176: } else { dvander@176: pPlugin->m_pub_funcs = NULL; dvander@176: } dvander@176: dvander@173: return pPlugin; dvander@173: } dvander@173: dvander@176: IPluginFunction *CPlugin::GetFunctionById(funcid_t func_id) dvander@176: { dvander@176: CFunction *pFunc = NULL; dvander@176: funcid_t save = func_id; dvander@176: dvander@176: if (func_id & 1) dvander@176: { dvander@176: func_id >>= 1; dvander@176: if (func_id >= m_plugin->info.publics_num) dvander@176: { dvander@176: return NULL; dvander@176: } dvander@176: pFunc = m_pub_funcs[func_id]; dvander@176: if (!pFunc) dvander@176: { dvander@176: pFunc = g_PluginMngr.GetFunctionFromPool(save, this); dvander@176: m_pub_funcs[func_id] = pFunc; dvander@176: } dvander@176: } else { dvander@176: func_id >>= 1; dvander@176: unsigned int index; dvander@176: if (!g_pVM->FunctionLookup(m_ctx_current.ctx, func_id, &index)) dvander@176: { dvander@176: return NULL; dvander@176: } dvander@176: pFunc = m_priv_funcs[func_id]; dvander@176: if (!pFunc) dvander@176: { dvander@176: pFunc = g_PluginMngr.GetFunctionFromPool(save, this); dvander@176: m_priv_funcs[func_id] = pFunc; dvander@176: } dvander@176: } dvander@176: dvander@176: return pFunc; dvander@176: } dvander@176: dvander@176: IPluginFunction *CPlugin::GetFunctionByName(const char *public_name) dvander@176: { dvander@176: uint32_t index; dvander@176: IPluginContext *base = m_ctx_current.base; dvander@176: dvander@176: if (base->FindPublicByName(public_name, &index) != SP_ERROR_NONE) dvander@176: { dvander@176: return NULL; dvander@176: } dvander@176: dvander@176: CFunction *pFunc = m_pub_funcs[index]; dvander@176: if (!pFunc) dvander@176: { dvander@176: sp_public_t *pub = NULL; dvander@176: base->GetPublicByIndex(index, &pub); dvander@176: if (pub) dvander@176: { dvander@176: pFunc = g_PluginMngr.GetFunctionFromPool(pub->funcid, this); dvander@176: m_pub_funcs[index] = pFunc; dvander@176: } dvander@176: } dvander@176: dvander@176: return pFunc; dvander@176: } dvander@176: dvander@173: void CPlugin::UpdateInfo() dvander@173: { dvander@173: /* Now grab the info */ dvander@173: uint32_t idx; dvander@173: IPluginContext *base = GetBaseContext(); dvander@173: int err = base->FindPubvarByName("myinfo", &idx); dvander@173: dvander@173: if (err == SP_ERROR_NONE) dvander@173: { dvander@173: struct sm_plugininfo_c_t dvander@173: { dvander@173: cell_t name; dvander@173: cell_t description; dvander@173: cell_t author; dvander@173: cell_t version; dvander@173: cell_t url; dvander@173: }; dvander@173: sm_plugininfo_c_t *cinfo; dvander@173: cell_t local_addr; dvander@173: dvander@173: base->GetPubvarAddrs(idx, &local_addr, (cell_t **)&cinfo); dvander@173: base->LocalToString(cinfo->name, (char **)&m_info.name); dvander@173: base->LocalToString(cinfo->description, (char **)&m_info.description); dvander@173: base->LocalToString(cinfo->author, (char **)&m_info.author); dvander@173: base->LocalToString(cinfo->url, (char **)&m_info.url); dvander@173: base->LocalToString(cinfo->version, (char **)&m_info.version); dvander@173: } dvander@173: dvander@173: m_info.author = m_info.author ? m_info.author : ""; dvander@173: m_info.description = m_info.description ? m_info.description : ""; dvander@173: m_info.name = m_info.name ? m_info.name : ""; dvander@173: m_info.url = m_info.url ? m_info.url : ""; dvander@173: m_info.version = m_info.version ? m_info.version : ""; dvander@173: } dvander@173: dvander@173: const sp_plugin_t *CPlugin::GetPluginStructure() const dvander@173: { dvander@173: return m_plugin; dvander@173: } dvander@173: dvander@173: IPluginContext *CPlugin::GetBaseContext() const dvander@173: { dvander@173: return m_ctx_current.base; dvander@173: } dvander@173: dvander@173: sp_context_t *CPlugin::GetContext() const dvander@173: { dvander@173: return m_ctx_current.ctx; dvander@173: } dvander@173: dvander@173: const char *CPlugin::GetFilename() const dvander@173: { dvander@173: return m_filename; dvander@173: } dvander@173: dvander@174: PluginType CPlugin::GetType() const dvander@173: { dvander@174: return m_type; dvander@173: } dvander@173: dvander@173: const sm_plugininfo_t *CPlugin::GetPublicInfo() const dvander@173: { dvander@173: return &m_info; dvander@173: } dvander@173: dvander@173: unsigned int CPlugin::GetSerial() const dvander@173: { dvander@173: return m_serial; dvander@173: } dvander@173: dvander@173: PluginStatus CPlugin::GetStatus() const dvander@173: { dvander@173: return m_status; dvander@173: } dvander@173: dvander@173: bool CPlugin::IsDebugging() const dvander@173: { dvander@173: return m_debugging; dvander@173: } dvander@173: dvander@173: bool CPlugin::SetPauseState(bool paused) dvander@173: { dvander@173: if (paused && GetStatus() != Plugin_Paused) dvander@173: { dvander@173: return false; dvander@173: } else if (!paused && GetStatus() != Plugin_Running) { dvander@173: return false; dvander@173: } dvander@173: dvander@173: /* :TODO: execute some forwards or some crap */ dvander@173: dvander@173: return true; dvander@173: } dvander@174: dvander@174: /******************* dvander@174: * PLUGIN ITERATOR * dvander@174: *******************/ dvander@190: dvander@174: CPluginManager::CPluginIterator::CPluginIterator(List *_mylist) dvander@174: { dvander@174: mylist = _mylist; dvander@174: } dvander@174: dvander@174: IPlugin *CPluginManager::CPluginIterator::GetPlugin() dvander@174: { dvander@174: return (*current); dvander@174: } dvander@174: dvander@174: bool CPluginManager::CPluginIterator::MorePlugins() dvander@174: { dvander@174: return (current != mylist->end()); dvander@174: } dvander@174: dvander@174: void CPluginManager::CPluginIterator::NextPlugin() dvander@174: { dvander@174: current++; dvander@174: } dvander@174: dvander@174: void CPluginManager::CPluginIterator::Release() dvander@174: { dvander@174: g_PluginMngr.ReleaseIterator(this); dvander@174: } dvander@174: dvander@174: CPluginManager::CPluginIterator::~CPluginIterator() dvander@174: { dvander@174: } dvander@174: dvander@174: void CPluginManager::CPluginIterator::Reset() dvander@174: { dvander@174: current = mylist->begin(); dvander@174: } dvander@174: dvander@174: /****************** dvander@174: * PLUGIN MANAGER * dvander@174: ******************/ dvander@174: dvander@190: void CPluginManager::RefreshOrLoadPlugins(const char *basedir) dvander@190: { dvander@190: IDirectory *dir = g_LibSys.OpenDirectory(basedir); dvander@190: while (dir->MoreFiles()) dvander@190: { dvander@190: if (dir->IsEntryDirectory() && (strcmp(dir->GetEntryName(), "disabled") != 0)) dvander@190: { dvander@190: char path[PLATFORM_MAX_PATH+1]; dvander@190: g_SMAPI->PathFormat(path, sizeof(path)-1, "%s/%s", basedir, dir->GetEntryName()); dvander@190: RefreshOrLoadPlugins(basedir); dvander@190: } dvander@190: } dvander@190: g_LibSys.CloseDirectory(dir); dvander@190: } dvander@190: dvander@174: IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType type, char error[], size_t err_max) dvander@174: { dvander@174: CPlugin *pPlugin = CPlugin::CreatePlugin(path, debug, type, error, err_max); dvander@174: dvander@174: if (!pPlugin) dvander@174: { dvander@174: return NULL; dvander@174: } dvander@174: dvander@174: m_plugins.push_back(pPlugin); dvander@174: dvander@174: List::iterator iter; dvander@174: IPluginsListener *pListener; dvander@174: for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++) dvander@174: { dvander@174: pListener = (*iter); dvander@174: pListener->OnPluginCreated(pPlugin); dvander@174: } dvander@174: dvander@174: /* :TODO: a lot more... */ dvander@174: dvander@174: return pPlugin; dvander@174: } dvander@174: dvander@174: bool CPluginManager::UnloadPlugin(IPlugin *plugin) dvander@174: { dvander@174: CPlugin *pPlugin = (CPlugin *)plugin; dvander@174: dvander@174: /* :TODO: More */ dvander@174: dvander@174: List::iterator iter; dvander@174: IPluginsListener *pListener; dvander@174: for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++) dvander@174: { dvander@174: pListener = (*iter); dvander@174: pListener->OnPluginDestroyed(pPlugin); dvander@174: } dvander@176: dvander@176: if (pPlugin->m_pub_funcs) dvander@176: { dvander@176: for (uint32_t i=0; im_plugin->info.publics_num; i++) dvander@176: { dvander@177: g_PluginMngr.ReleaseFunctionToPool(pPlugin->m_pub_funcs[i]); dvander@176: } dvander@176: delete [] pPlugin->m_pub_funcs; dvander@176: pPlugin->m_pub_funcs = NULL; dvander@176: } dvander@176: dvander@176: if (pPlugin->m_priv_funcs) dvander@176: { dvander@176: for (unsigned int i=0; im_funcsnum; i++) dvander@176: { dvander@177: g_PluginMngr.ReleaseFunctionToPool(pPlugin->m_priv_funcs[i]); dvander@176: } dvander@176: delete [] pPlugin->m_priv_funcs; dvander@176: pPlugin->m_priv_funcs = NULL; dvander@176: } dvander@174: dvander@174: if (pPlugin->m_ctx_current.base) dvander@174: { dvander@174: g_pSourcePawn->FreeBaseContext(pPlugin->m_ctx_current.base); dvander@174: } dvander@174: if (pPlugin->m_ctx_backup.base) dvander@174: { dvander@174: g_pSourcePawn->FreeBaseContext(pPlugin->m_ctx_backup.base); dvander@174: } dvander@174: if (pPlugin->m_ctx_current.ctx) dvander@174: { dvander@174: pPlugin->m_ctx_current.ctx->vmbase->FreeContext(pPlugin->m_ctx_current.ctx); dvander@174: } dvander@174: if (pPlugin->m_ctx_backup.ctx) dvander@174: { dvander@174: pPlugin->m_ctx_backup.ctx->vmbase->FreeContext(pPlugin->m_ctx_backup.ctx); dvander@174: } dvander@174: dvander@174: g_pSourcePawn->FreeFromMemory(pPlugin->m_plugin); dvander@174: dvander@174: delete pPlugin; dvander@174: dvander@174: return true; dvander@174: } dvander@174: dvander@174: IPlugin *CPluginManager::FindPluginByContext(const sp_context_t *ctx) dvander@174: { dvander@174: IPlugin *pl = (IPlugin *)ctx->user[SM_CONTEXTVAR_MYSELF]; dvander@174: return pl; dvander@174: } dvander@174: dvander@174: unsigned int CPluginManager::GetPluginCount() dvander@174: { dvander@174: return m_plugins.size(); dvander@174: } dvander@174: dvander@174: void CPluginManager::AddPluginsListener(IPluginsListener *listener) dvander@174: { dvander@174: m_listeners.push_back(listener); dvander@174: } dvander@174: dvander@174: void CPluginManager::RemovePluginsListener(IPluginsListener *listener) dvander@174: { dvander@174: m_listeners.remove(listener); dvander@174: } dvander@174: dvander@174: IPluginIterator *CPluginManager::GetPluginIterator() dvander@174: { dvander@174: if (m_iters.empty()) dvander@174: { dvander@174: return new CPluginIterator(&m_plugins); dvander@174: } else { dvander@174: CPluginIterator *iter = m_iters.front(); dvander@174: m_iters.pop(); dvander@174: return iter; dvander@174: } dvander@174: } dvander@174: dvander@174: void CPluginManager::ReleaseIterator(CPluginIterator *iter) dvander@174: { dvander@174: m_iters.push(iter); dvander@174: } dvander@176: dvander@176: void CPluginManager::ReleaseFunctionToPool(CFunction *func) dvander@176: { dvander@177: if (!func) dvander@177: { dvander@177: return; dvander@177: } dvander@177: func->Cancel(); dvander@176: m_funcpool.push(func); dvander@176: } dvander@176: dvander@176: CFunction *CPluginManager::GetFunctionFromPool(funcid_t f, CPlugin *plugin) dvander@176: { dvander@176: if (m_funcpool.empty()) dvander@176: { dvander@176: return new CFunction(f, plugin); dvander@176: } else { dvander@176: CFunction *func = m_funcpool.front(); dvander@176: m_funcpool.pop(); dvander@176: func->Set(f, plugin); dvander@176: return func; dvander@176: } dvander@176: } dvander@176: dvander@176: CPluginManager::~CPluginManager() dvander@176: { dvander@176: //:TODO: we need a good way to free what we're holding dvander@176: }