dvander@370: /**
ds@653: * vim: set ts=4 :
ds@1330: * =============================================================================
dvander@1231: * SourceMod
dvander@1231: * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
ds@1330: * =============================================================================
dvander@370: *
ds@1330: * This program is free software; you can redistribute it and/or modify it under
ds@1330: * the terms of the GNU General Public License, version 3.0, as published by the
ds@1330: * Free Software Foundation.
dvander@1231: *
ds@1330: * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1330: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1330: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
ds@1330: * details.
dvander@1231: *
ds@1330: * You should have received a copy of the GNU General Public License along with
ds@1330: * this program. If not, see .
dvander@1231: *
ds@1330: * As a special exception, AlliedModders LLC gives you permission to link the
ds@1330: * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1330: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1330: * by the Valve Corporation. You must obey the GNU General Public License in
ds@1330: * all respects for all other code used. Additionally, AlliedModders LLC grants
ds@1330: * this exception to all derivative works. AlliedModders LLC defines further
ds@1330: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1330: * or .
dvander@370: *
dvander@370: * Version: $Id$
dvander@370: */
dvander@370:
dvander@173: #include
dvander@173: #include "PluginSys.h"
dvander@229: #include "ShareSys.h"
dvander@190: #include "LibrarySys.h"
dvander@220: #include "HandleSys.h"
ds@611: #include "ForwardSys.h"
dvander@197: #include "sourcemm_api.h"
dvander@209: #include "sourcemod.h"
dvander@591: #include "TextParsers.h"
dvander@592: #include "Logger.h"
dvander@298: #include "ExtensionSys.h"
dvander@309: #include "sm_srvcmds.h"
dvander@309: #include "sm_stringutil.h"
dvander@848: #include "ConCmdManager.h"
dvander@848: #include "PlayerManager.h"
dvander@978: #include "CoreConfig.h"
dvander@173:
dvander@211: CPluginManager g_PluginSys;
dvander@220: HandleType_t g_PluginType = 0;
dvander@229: IdentityType_t g_PluginIdent = 0;
dvander@173:
dvander@209: CPlugin::CPlugin(const char *file)
dvander@209: {
dvander@209: static int MySerial = 0;
dvander@209:
dvander@209: m_type = PluginType_Private;
dvander@209: m_status = Plugin_Uncompiled;
dvander@209: m_serial = ++MySerial;
dvander@209: m_plugin = NULL;
dvander@209: m_errormsg[256] = '\0';
dvander@209: snprintf(m_filename, sizeof(m_filename), "%s", file);
dvander@229: m_handle = 0;
dvander@229: m_ident = NULL;
dvander@486: m_pProps = sm_trie_create();
dvander@605: m_FakeNativesMissing = false;
faluco@1112: m_LibraryMissing = false;
dvander@209: }
dvander@209:
dvander@209: CPlugin::~CPlugin()
dvander@173: {
dvander@298: if (m_handle)
dvander@298: {
dvander@298: HandleSecurity sec;
dvander@298: sec.pOwner = g_PluginSys.GetIdentity();
dvander@298: sec.pIdentity = sec.pOwner;
dvander@298:
dvander@298: g_HandleSys.FreeHandle(m_handle, &sec);
dvander@298: g_ShareSys.DestroyIdentity(m_ident);
dvander@298: }
dvander@298:
dvander@209: if (m_ctx.base)
dvander@209: {
dvander@262: delete m_ctx.base;
dvander@209: m_ctx.base = NULL;
dvander@209: }
dvander@209: if (m_ctx.ctx)
dvander@209: {
dvander@209: m_ctx.vm->FreeContext(m_ctx.ctx);
dvander@209: m_ctx.ctx = NULL;
dvander@209: }
dvander@209: if (m_ctx.co)
dvander@209: {
dvander@209: m_ctx.vm->AbortCompilation(m_ctx.co);
dvander@209: m_ctx.co = NULL;
dvander@209: }
dvander@209:
dvander@222: if (m_plugin)
dvander@222: {
dvander@222: g_pSourcePawn->FreeFromMemory(m_plugin);
dvander@222: m_plugin = NULL;
dvander@222: }
faluco@641: if (m_pProps)
dvander@486: {
dvander@486: sm_trie_destroy(m_pProps);
dvander@486: }
dvander@978: for (size_t i=0; iSetIdentity(m_ident);
dvander@229: }
dvander@209: }
dvander@209:
dvander@536: Handle_t CPlugin::GetMyHandle()
dvander@536: {
dvander@536: return m_handle;
dvander@536: }
dvander@536:
dvander@209: CPlugin *CPlugin::CreatePlugin(const char *file, char *error, size_t maxlength)
dvander@209: {
ds@652: char fullpath[PLATFORM_MAX_PATH];
dvander@317: g_SourceMod.BuildPath(Path_SM, fullpath, sizeof(fullpath), "plugins/%s", file);
dvander@209: FILE *fp = fopen(fullpath, "rb");
dvander@173:
dvander@298: CPlugin *pPlugin = new CPlugin(file);
dvander@298:
dvander@173: if (!fp)
dvander@173: {
dvander@209: if (error)
dvander@209: {
dvander@209: snprintf(error, maxlength, "Unable to open file");
dvander@209: }
dvander@298: pPlugin->m_status = Plugin_BadLoad;
dvander@298: return pPlugin;
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@209: fclose(fp);
dvander@209: if (error)
dvander@209: {
dvander@209: snprintf(error, maxlength, "Error %d while parsing plugin", err);
dvander@209: }
dvander@298: pPlugin->m_status = Plugin_BadLoad;
dvander@298: return pPlugin;
dvander@173: }
dvander@173:
dvander@173: fclose(fp);
dvander@173:
dvander@209: pPlugin->m_plugin = pl;
dvander@298:
dvander@209: return pPlugin;
dvander@209: }
dvander@209:
dvander@486: bool CPlugin::GetProperty(const char *prop, void **ptr, bool remove/* =false */)
dvander@486: {
dvander@486: bool exists = sm_trie_retrieve(m_pProps, prop, ptr);
dvander@486:
dvander@486: if (exists && remove)
dvander@486: {
dvander@486: sm_trie_delete(m_pProps, prop);
dvander@486: }
dvander@486:
dvander@486: return exists;
dvander@486: }
dvander@486:
dvander@486: bool CPlugin::SetProperty(const char *prop, void *ptr)
dvander@486: {
dvander@486: return sm_trie_insert(m_pProps, prop, ptr);
dvander@486: }
dvander@486:
dvander@209: ICompilation *CPlugin::StartMyCompile(IVirtualMachine *vm)
dvander@209: {
dvander@209: if (!m_plugin)
dvander@173: {
dvander@209: return NULL;
dvander@173: }
dvander@173:
dvander@209: /* :NOTICE: We will eventually need to change these natives
dvander@209: * for swapping in new contexts
dvander@209: */
dvander@209: if (m_ctx.co || m_ctx.ctx)
dvander@173: {
dvander@173: return NULL;
dvander@173: }
dvander@173:
dvander@209: m_status = Plugin_Uncompiled;
dvander@173:
dvander@209: m_ctx.vm = vm;
dvander@209: m_ctx.co = vm->StartCompilation(m_plugin);
dvander@209:
dvander@209: return m_ctx.co;
dvander@209: }
dvander@173:
dvander@209: void CPlugin::CancelMyCompile()
dvander@209: {
dvander@209: if (!m_ctx.co)
dvander@209: {
dvander@209: return;
dvander@209: }
dvander@176:
dvander@209: m_ctx.vm->AbortCompilation(m_ctx.co);
dvander@209: m_ctx.co = NULL;
dvander@209: m_ctx.vm = NULL;
dvander@209: }
dvander@209:
dvander@209: bool CPlugin::FinishMyCompile(char *error, size_t maxlength)
dvander@209: {
dvander@209: if (!m_ctx.co)
dvander@176: {
dvander@209: return false;
dvander@176: }
dvander@176:
dvander@209: int err;
dvander@209: m_ctx.ctx = m_ctx.vm->CompileToContext(m_ctx.co, &err);
dvander@209: if (!m_ctx.ctx)
dvander@176: {
dvander@209: memset(&m_ctx, 0, sizeof(m_ctx));
dvander@298: if (error)
dvander@209: {
dvander@803: snprintf(error, maxlength, "JIT failed to compile (error %d)", err);
dvander@209: }
dvander@209: return false;
dvander@176: }
dvander@176:
dvander@262: m_ctx.base = new BaseContext(m_ctx.ctx);
dvander@209: m_ctx.ctx->user[SM_CONTEXTVAR_MYSELF] = (void *)this;
dvander@209:
dvander@211: m_status = Plugin_Created;
faluco@216: m_ctx.co = NULL;
dvander@211:
dvander@209: UpdateInfo();
dvander@209:
dvander@209: return true;
dvander@209: }
dvander@209:
dvander@209: void CPlugin::SetErrorState(PluginStatus status, const char *error_fmt, ...)
dvander@209: {
dvander@605: PluginStatus old_status = m_status;
dvander@209: m_status = status;
dvander@209:
dvander@605: if (old_status == Plugin_Running)
dvander@605: {
dvander@605: /* Tell everyone we're now paused */
dvander@605: g_PluginSys._SetPauseState(this, true);
dvander@605: }
dvander@605:
dvander@209: va_list ap;
dvander@209: va_start(ap, error_fmt);
dvander@209: vsnprintf(m_errormsg, sizeof(m_errormsg), error_fmt, ap);
dvander@209: va_end(ap);
dvander@173:
dvander@525: if (m_ctx.ctx)
dvander@176: {
dvander@525: m_ctx.ctx->flags |= SPFLAG_PLUGIN_PAUSED;
dvander@176: }
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@413: memset(&m_info, 0, sizeof(m_info));
dvander@413:
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:
ds@426: void CPlugin::Call_OnPluginStart()
dvander@211: {
dvander@211: if (m_status != Plugin_Loaded)
dvander@211: {
dvander@211: return;
dvander@211: }
dvander@211:
dvander@211: m_status = Plugin_Running;
dvander@211:
dvander@211: cell_t result;
dvander@340: IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("OnPluginStart");
dvander@211: if (!pFunction)
dvander@211: {
dvander@211: return;
dvander@211: }
dvander@211:
dvander@838: int err;
dvander@838: if ((err=pFunction->Execute(&result)) != SP_ERROR_NONE)
dvander@838: {
dvander@838: SetErrorState(Plugin_Error, "Error detected in plugin startup (see error logs)");
dvander@848: } else {
dvander@848: if (g_OnMapStarted)
dvander@848: {
dvander@848: if ((pFunction = m_ctx.base->GetFunctionByName("OnMapStart")) != NULL)
dvander@848: {
dvander@848: pFunction->Execute(NULL);
dvander@848: }
dvander@848: }
dvander@978: if (SM_AreConfigsExecuted())
dvander@848: {
dvander@978: SM_ExecuteForPlugin(GetBaseContext());
dvander@848: }
dvander@838: }
dvander@282: }
dvander@282:
ds@426: void CPlugin::Call_OnPluginEnd()
dvander@282: {
faluco@736: if (m_status > Plugin_Paused)
dvander@211: {
dvander@282: return;
dvander@211: }
dvander@282:
dvander@282: cell_t result;
dvander@340: IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("OnPluginEnd");
dvander@282: if (!pFunction)
dvander@282: {
dvander@282: return;
dvander@282: }
dvander@282:
dvander@282: pFunction->Execute(&result);
dvander@211: }
dvander@211:
faluco@1221: void CPlugin::Call_OnAllPluginsLoaded()
faluco@1221: {
faluco@1221: if (m_status > Plugin_Paused)
faluco@1221: {
faluco@1221: return;
faluco@1221: }
faluco@1221:
faluco@1221: cell_t result;
faluco@1221: IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("OnAllPluginsLoaded");
faluco@1221: if (!pFunction)
faluco@1221: {
faluco@1221: return;
faluco@1221: }
faluco@1221:
faluco@1221: pFunction->Execute(&result);
faluco@1221: }
faluco@1221:
dvander@211: bool CPlugin::Call_AskPluginLoad(char *error, size_t maxlength)
dvander@211: {
dvander@211: if (m_status != Plugin_Created)
dvander@211: {
dvander@211: return false;
dvander@211: }
dvander@211:
faluco@216: m_status = Plugin_Loaded;
faluco@216:
dvander@211: int err;
dvander@211: cell_t result;
dvander@327: IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("AskPluginLoad");
dvander@211:
dvander@211: if (!pFunction)
dvander@211: {
dvander@211: return true;
dvander@211: }
dvander@211:
dvander@222: pFunction->PushCell(m_handle);
dvander@211: pFunction->PushCell(g_PluginSys.IsLateLoadTime() ? 1 : 0);
dvander@211: pFunction->PushStringEx(error, maxlength, 0, SM_PARAM_COPYBACK);
dvander@211: pFunction->PushCell(maxlength);
dvander@211: if ((err=pFunction->Execute(&result)) != SP_ERROR_NONE)
dvander@211: {
dvander@211: return false;
dvander@211: }
dvander@211:
dvander@282: if (!result || m_status != Plugin_Loaded)
dvander@211: {
dvander@211: return false;
dvander@211: }
dvander@211:
dvander@211: return true;
dvander@211: }
dvander@211:
dvander@615: const sp_plugin_t *CPlugin::GetPluginStructure()
dvander@173: {
dvander@173: return m_plugin;
dvander@173: }
dvander@173:
dvander@615: IPluginContext *CPlugin::GetBaseContext()
dvander@173: {
dvander@209: return m_ctx.base;
dvander@173: }
dvander@173:
dvander@615: sp_context_t *CPlugin::GetContext()
dvander@173: {
dvander@209: return m_ctx.ctx;
dvander@173: }
dvander@173:
dvander@615: const char *CPlugin::GetFilename()
dvander@173: {
dvander@173: return m_filename;
dvander@173: }
dvander@173:
dvander@615: PluginType CPlugin::GetType()
dvander@173: {
dvander@174: return m_type;
dvander@173: }
dvander@173:
dvander@615: const sm_plugininfo_t *CPlugin::GetPublicInfo()
dvander@173: {
dvander@173: return &m_info;
dvander@173: }
dvander@173:
dvander@615: unsigned int CPlugin::GetSerial()
dvander@173: {
dvander@173: return m_serial;
dvander@173: }
dvander@173:
dvander@615: PluginStatus CPlugin::GetStatus()
dvander@173: {
dvander@173: return m_status;
dvander@173: }
dvander@173:
dvander@615: bool CPlugin::IsDebugging()
dvander@173: {
dvander@209: if (!m_ctx.ctx)
dvander@209: {
dvander@209: return false;
dvander@209: }
dvander@209:
dvander@209: return ((m_ctx.ctx->flags & SP_FLAG_DEBUG) == SP_FLAG_DEBUG);
dvander@173: }
dvander@173:
dvander@1124: void CPlugin::LibraryActions(bool dropping)
dvander@1124: {
dvander@1124: List::iterator iter;
dvander@1124: for (iter = m_Libraries.begin();
dvander@1124: iter != m_Libraries.end();
dvander@1124: iter++)
dvander@1124: {
dvander@1124: g_PluginSys.OnLibraryAction((*iter).c_str(), dropping);
dvander@1124: }
dvander@1124: }
dvander@1124:
dvander@173: bool CPlugin::SetPauseState(bool paused)
dvander@173: {
dvander@1124: if (paused && GetStatus() != Plugin_Running)
dvander@173: {
dvander@173: return false;
dvander@1124: } else if (!paused && GetStatus() != Plugin_Paused) {
dvander@173: return false;
dvander@173: }
dvander@282:
dvander@1124: if (paused)
dvander@1124: {
dvander@1124: LibraryActions(true);
dvander@1124: }
dvander@1124:
dvander@327: IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("OnPluginPauseChange");
dvander@282: if (pFunction)
dvander@282: {
dvander@282: cell_t result;
dvander@282: pFunction->PushCell(paused ? 1 : 0);
dvander@282: pFunction->Execute(&result);
dvander@282: }
dvander@173:
dvander@525: if (paused)
dvander@525: {
dvander@525: m_status = Plugin_Paused;
dvander@525: m_ctx.ctx->flags |= SPFLAG_PLUGIN_PAUSED;
dvander@525: } else {
dvander@525: m_status = Plugin_Running;
dvander@525: m_ctx.ctx->flags &= ~SPFLAG_PLUGIN_PAUSED;
dvander@525: }
dvander@525:
faluco@430: g_PluginSys._SetPauseState(this, paused);
faluco@430:
dvander@1124: if (!paused)
dvander@1124: {
dvander@1124: LibraryActions(false);
dvander@1124: }
dvander@1124:
dvander@173: return true;
dvander@173: }
dvander@174:
dvander@615: IdentityToken_t *CPlugin::GetIdentity()
dvander@220: {
dvander@229: return m_ident;
dvander@220: }
dvander@220:
dvander@309: bool CPlugin::ToggleDebugMode(bool debug, char *error, size_t maxlength)
faluco@290: {
faluco@290: int err;
faluco@290:
faluco@290: if (!IsRunnable())
faluco@290: {
dvander@309: if (error)
dvander@309: {
dvander@309: snprintf(error, maxlength, "Plugin is not runnable.");
dvander@309: }
faluco@290: return false;
faluco@290: }
faluco@290:
dvander@309: if (debug && IsDebugging())
faluco@290: {
dvander@309: if (error)
dvander@309: {
dvander@309: snprintf(error, maxlength, "Plugin is already in debug mode.");
dvander@309: }
dvander@309: return false;
dvander@309: } else if (!debug && !IsDebugging()) {
dvander@309: if (error)
dvander@309: {
dvander@309: snprintf(error, maxlength, "Plugins is already in production mode.");
dvander@309: }
faluco@290: return false;
faluco@290: }
dvander@309:
faluco@290: ICompilation *co = g_pVM->StartCompilation(m_ctx.ctx->plugin);
faluco@290: if (!g_pVM->SetCompilationOption(co, "debug", (debug) ? "1" : "0"))
faluco@290: {
dvander@309: if (error)
dvander@309: {
dvander@309: snprintf(error, maxlength, "Failed to change plugin mode (JIT failure).");
dvander@309: }
faluco@290: return false;
faluco@290: }
dvander@309:
faluco@290: sp_context_t *new_ctx = g_pVM->CompileToContext(co, &err);
faluco@290:
dvander@309: if (new_ctx)
dvander@309: {
dvander@309: memcpy(new_ctx->memory, m_ctx.ctx->memory, m_ctx.ctx->mem_size);
dvander@309: new_ctx->hp = m_ctx.ctx->hp;
dvander@309: new_ctx->sp = m_ctx.ctx->sp;
dvander@309: new_ctx->frm = m_ctx.ctx->frm;
dvander@309: new_ctx->dbreak = m_ctx.ctx->dbreak;
dvander@309: new_ctx->context = m_ctx.ctx->context;
dvander@309: memcpy(new_ctx->user, m_ctx.ctx->user, sizeof(m_ctx.ctx->user));
faluco@290:
dvander@693: uint32_t nativeCount = m_plugin->info.natives_num;
dvander@693: for (uint32_t i=0; inatives[i].pfn = m_ctx.ctx->natives[i].pfn;
dvander@693: new_ctx->natives[i].status = m_ctx.ctx->natives[i].status;
dvander@693: }
dvander@693:
dvander@309: g_pVM->FreeContext(m_ctx.ctx);
dvander@309: m_ctx.ctx = new_ctx;
dvander@309: m_ctx.base->SetContext(new_ctx);
faluco@290:
dvander@309: UpdateInfo();
dvander@309: } else {
dvander@309: if (error)
dvander@309: {
dvander@309: snprintf(error, maxlength, "Failed to recompile plugin (JIT error %d).", err);
dvander@309: }
dvander@309: return false;
dvander@309: }
faluco@290:
faluco@290: return true;
faluco@290: }
faluco@290:
dvander@615: bool CPlugin::IsRunnable()
faluco@290: {
faluco@290: return (m_status <= Plugin_Paused) ? true : false;
faluco@290: }
faluco@290:
faluco@333: time_t CPlugin::GetFileTimeStamp()
faluco@333: {
ds@652: char path[PLATFORM_MAX_PATH];
faluco@333: g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "plugins/%s", m_filename);
faluco@333: #ifdef PLATFORM_WINDOWS
faluco@333: struct _stat s;
faluco@333: if (_stat(path, &s) != 0)
dvander@351: #elif defined PLATFORM_POSIX
faluco@333: struct stat s;
faluco@333: if (stat(path, &s) != 0)
faluco@333: #endif
faluco@333: {
faluco@333: return 0;
faluco@333: } else {
faluco@333: return s.st_mtime;
faluco@333: }
faluco@333: }
faluco@333:
dvander@615: time_t CPlugin::GetTimeStamp()
faluco@333: {
faluco@333: return m_LastAccess;
faluco@333: }
faluco@333:
faluco@333: void CPlugin::SetTimeStamp(time_t t)
faluco@333: {
faluco@333: m_LastAccess = t;
faluco@333: }
faluco@333:
faluco@389: void CPlugin::AddLangFile(unsigned int index)
faluco@389: {
faluco@389: m_PhraseFiles.push_back(index);
faluco@389: }
faluco@389:
dvander@615: size_t CPlugin::GetLangFileCount()
faluco@389: {
faluco@389: return m_PhraseFiles.size();
faluco@389: }
faluco@389:
dvander@615: unsigned int CPlugin::GetLangFileByIndex(unsigned int index)
faluco@389: {
faluco@389: return m_PhraseFiles.at(index);
faluco@389: }
faluco@389:
dvander@605: void CPlugin::DependencyDropped(CPlugin *pOwner)
dvander@605: {
dvander@605: if (!m_ctx.ctx)
dvander@605: {
dvander@605: return;
dvander@605: }
dvander@605:
faluco@1112: List::iterator reqlib_iter;
faluco@1112: List::iterator lib_iter;
faluco@1112: for (lib_iter=pOwner->m_Libraries.begin(); lib_iter!=pOwner->m_Libraries.end(); lib_iter++)
faluco@1112: {
faluco@1112: for (reqlib_iter=m_RequiredLibs.begin(); reqlib_iter!=m_RequiredLibs.end(); reqlib_iter++)
faluco@1112: {
faluco@1112: if ((*reqlib_iter) == (*lib_iter))
faluco@1112: {
faluco@1112: m_LibraryMissing = true;
faluco@1112: }
faluco@1112: }
faluco@1112: }
faluco@1112:
dvander@605: List::iterator iter;
dvander@605: FakeNative *pNative;
dvander@605: sp_native_t *native;
dvander@605: uint32_t idx;
dvander@605: unsigned int unbound = 0;
dvander@605:
dvander@605: for (iter = pOwner->m_fakeNatives.begin();
dvander@605: iter != pOwner->m_fakeNatives.end();
dvander@605: iter++)
dvander@605: {
dvander@605: pNative = (*iter);
dvander@605: /* Find this native! */
dvander@605: if (m_ctx.base->FindNativeByName(pNative->name.c_str(), &idx) != SP_ERROR_NONE)
dvander@605: {
dvander@605: continue;
dvander@605: }
dvander@605: /* Unbind it */
dvander@605: m_ctx.base->GetNativeByIndex(idx, &native);
dvander@605: native->pfn = NULL;
dvander@605: native->status = SP_NATIVE_UNBOUND;
dvander@605: unbound++;
dvander@605: }
dvander@605:
dvander@605: if (unbound)
dvander@605: {
dvander@605: m_FakeNativesMissing = true;
faluco@1112: }
faluco@1112:
faluco@1112: /* :IDEA: in the future, add native trapping? */
faluco@1112: if (m_FakeNativesMissing || m_LibraryMissing)
faluco@1112: {
dvander@605: SetErrorState(Plugin_Error, "Depends on plugin: %s", pOwner->GetFilename());
dvander@605: }
dvander@605:
dvander@605: m_dependsOn.remove(pOwner);
dvander@605: }
dvander@605:
dvander@978: unsigned int CPlugin::GetConfigCount()
dvander@978: {
dvander@978: return (unsigned int)m_configs.size();
dvander@978: }
dvander@978:
dvander@978: AutoConfig *CPlugin::GetConfig(unsigned int i)
dvander@978: {
dvander@978: if (i >= GetConfigCount())
dvander@978: {
dvander@978: return NULL;
dvander@978: }
dvander@978:
dvander@978: return m_configs[i];
dvander@978: }
dvander@978:
dvander@978: void CPlugin::AddConfig(bool autoCreate, const char *cfg, const char *folder)
dvander@978: {
dvander@978: AutoConfig *c = new AutoConfig;
dvander@978:
dvander@978: c->autocfg = cfg;
dvander@978: c->folder = folder;
dvander@978: c->create = autoCreate;
dvander@978:
dvander@978: m_configs.push_back(c);
dvander@978: }
dvander@978:
dvander@174: /*******************
dvander@174: * PLUGIN ITERATOR *
dvander@174: *******************/
dvander@190:
dvander@213: CPluginManager::CPluginIterator::CPluginIterator(List *_mylist)
dvander@174: {
dvander@174: mylist = _mylist;
faluco@216: Reset();
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@211: g_PluginSys.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@211: CPluginManager::CPluginManager()
dvander@211: {
dvander@211: m_LoadLookup = sm_trie_create();
dvander@211: m_AllPluginsLoaded = false;
dvander@229: m_MyIdent = NULL;
dvander@601: m_pNativeLookup = sm_trie_create();
dvander@1382: m_pCoreNatives = sm_trie_create();
dvander@211: }
dvander@211:
dvander@211: CPluginManager::~CPluginManager()
dvander@211: {
dvander@282: /* :NOTICE:
dvander@282: * Ignore the fact that there might be plugins in the cache.
dvander@282: * This usually means that Core is not being unloaded properly, and everything
dvander@282: * will crash anyway. YAY
dvander@282: */
dvander@211: sm_trie_destroy(m_LoadLookup);
dvander@601: sm_trie_destroy(m_pNativeLookup);
dvander@1382: sm_trie_destroy(m_pCoreNatives);
faluco@641:
faluco@641: CStack::iterator iter;
faluco@641: for (iter=m_iters.begin(); iter!=m_iters.end(); iter++)
faluco@641: {
faluco@641: delete (*iter);
faluco@641: }
faluco@641: m_iters.popall();
dvander@211: }
dvander@211:
dvander@1018: void CPluginManager::Shutdown()
dvander@1018: {
dvander@1018: List::iterator iter;
dvander@1018:
dvander@1018: while ((iter = m_plugins.begin()) != m_plugins.end())
dvander@1018: {
dvander@1018: UnloadPlugin(*iter);
dvander@1018: }
dvander@1018: }
dvander@1018:
dvander@213: void CPluginManager::LoadAll_FirstPass(const char *config, const char *basedir)
dvander@190: {
dvander@203: /* First read in the database of plugin settings */
dvander@203: SMCParseError err;
dvander@203: unsigned int line, col;
faluco@216: m_AllPluginsLoaded = false;
dvander@1406: if ((err=textparsers->ParseFile_SMC(config, &m_PluginInfo, &line, &col)) != SMCParse_Okay)
dvander@203: {
dvander@305: g_Logger.LogError("[SM] Encountered fatal error parsing file \"%s\"", config);
dvander@1406: const char *err_msg = textparsers->GetSMCErrorString(err);
dvander@282: if (err_msg)
dvander@282: {
dvander@305: g_Logger.LogError("[SM] Parse error encountered: \"%s\"", err_msg);
dvander@282: }
dvander@203: }
dvander@203:
dvander@209: LoadPluginsFromDir(basedir, NULL);
dvander@209: }
dvander@203:
dvander@209: void CPluginManager::LoadPluginsFromDir(const char *basedir, const char *localpath)
dvander@209: {
ds@652: char base_path[PLATFORM_MAX_PATH];
dvander@209:
dvander@209: /* Form the current path to start reading from */
dvander@209: if (localpath == NULL)
dvander@209: {
dvander@209: g_LibSys.PathFormat(base_path, sizeof(base_path), "%s", basedir);
dvander@209: } else {
dvander@209: g_LibSys.PathFormat(base_path, sizeof(base_path), "%s/%s", basedir, localpath);
dvander@209: }
dvander@209:
dvander@209: IDirectory *dir = g_LibSys.OpenDirectory(base_path);
dvander@209:
dvander@209: if (!dir)
dvander@209: {
dvander@282: char error[256];
dvander@282: g_LibSys.GetPlatformError(error, sizeof(error));
dvander@305: g_Logger.LogError("[SM] Failure reading from plugins path: %s", localpath);
dvander@305: g_Logger.LogError("[SM] Platform returned error: %s", error);
dvander@209: return;
dvander@209: }
dvander@209:
dvander@190: while (dir->MoreFiles())
dvander@190: {
dvander@209: if (dir->IsEntryDirectory()
dvander@209: && (strcmp(dir->GetEntryName(), ".") != 0)
dvander@209: && (strcmp(dir->GetEntryName(), "..") != 0)
dvander@209: && (strcmp(dir->GetEntryName(), "disabled") != 0)
dvander@209: && (strcmp(dir->GetEntryName(), "optional") != 0))
dvander@190: {
ds@652: char new_local[PLATFORM_MAX_PATH];
dvander@209: if (localpath == NULL)
dvander@209: {
dvander@209: /* If no path yet, don't add a former slash */
dvander@209: snprintf(new_local, sizeof(new_local), "%s", dir->GetEntryName());
dvander@209: } else {
dvander@209: g_LibSys.PathFormat(new_local, sizeof(new_local), "%s/%s", localpath, dir->GetEntryName());
dvander@209: }
dvander@209: LoadPluginsFromDir(basedir, new_local);
dvander@209: } else if (dir->IsEntryFile()) {
dvander@209: const char *name = dir->GetEntryName();
dvander@209: size_t len = strlen(name);
dvander@211: if (len >= 4
dvander@211: && strcmp(&name[len-4], ".smx") == 0)
dvander@209: {
dvander@211: /* If the filename matches, load the plugin */
ds@652: char plugin[PLATFORM_MAX_PATH];
dvander@211: if (localpath == NULL)
dvander@211: {
dvander@211: snprintf(plugin, sizeof(plugin), "%s", name);
dvander@211: } else {
dvander@211: g_LibSys.PathFormat(plugin, sizeof(plugin), "%s/%s", localpath, name);
dvander@211: }
dvander@211: LoadAutoPlugin(plugin);
dvander@209: }
dvander@209: }
dvander@209: dir->NextEntry();
dvander@209: }
dvander@209: g_LibSys.CloseDirectory(dir);
dvander@209: }
dvander@209:
dvander@211: //well i have discovered that gabe newell is very fat, so i wrote this comment now
ds@755: LoadRes CPluginManager::_LoadPlugin(CPlugin **_plugin, const char *path, bool debug, PluginType type, char error[], size_t maxlength)
dvander@209: {
dvander@1436: bool no_load = false;
dvander@1436: PluginSettings *pset;
dvander@1436: unsigned int setcount = m_PluginInfo.GetSettingsNum();
dvander@1436: for (unsigned int i=0; iblockload_val)
dvander@1436: {
dvander@1436: no_load = true;
dvander@1436: break;
dvander@1436: }
dvander@1436: }
dvander@1436:
dvander@211: /**
dvander@211: * Does this plugin already exist?
dvander@211: */
dvander@211: CPlugin *pPlugin;
dvander@298: if (sm_trie_retrieve(m_LoadLookup, path, (void **)&pPlugin))
dvander@211: {
dvander@211: /* Check to see if we should try reloading it */
dvander@211: if (pPlugin->GetStatus() == Plugin_BadLoad
dvander@282: || pPlugin->GetStatus() == Plugin_Error
dvander@1436: || pPlugin->GetStatus() == Plugin_Failed
dvander@1436: || no_load)
dvander@211: {
dvander@211: UnloadPlugin(pPlugin);
faluco@383: } else {
faluco@383: if (_plugin)
faluco@383: {
faluco@383: *_plugin = pPlugin;
faluco@383: }
faluco@383: return LoadRes_AlreadyLoaded;
dvander@211: }
dvander@211: }
dvander@211:
dvander@1436: if (no_load)
dvander@1436: {
dvander@1436: return LoadRes_NeverLoad;
dvander@1436: }
dvander@1436:
ds@755: pPlugin = CPlugin::CreatePlugin(path, error, maxlength);
dvander@209:
dvander@209: assert(pPlugin != NULL);
dvander@209:
dvander@209: pPlugin->m_type = PluginType_MapUpdated;
dvander@209:
dvander@209: ICompilation *co = NULL;
dvander@209:
dvander@209: if (pPlugin->m_status == Plugin_Uncompiled)
dvander@209: {
dvander@209: co = pPlugin->StartMyCompile(g_pVM);
dvander@209: }
dvander@209:
dvander@209: for (unsigned int i=0; im_type = pset->type_val;
dvander@209: if (co)
dvander@209: {
dvander@209: for (unsigned int j=0; jopts_num; j++)
dvander@209: {
dvander@209: const char *key, *val;
dvander@209: m_PluginInfo.GetOptionsForPlugin(pset, j, &key, &val);
dvander@209: if (!key || !val)
dvander@209: {
dvander@209: continue;
dvander@209: }
dvander@209: if (!g_pVM->SetCompilationOption(co, key, val))
dvander@209: {
dvander@298: if (error)
dvander@298: {
ds@755: snprintf(error, maxlength, "Unable to set JIT option (key \"%s\") (value \"%s\")", key, val);
dvander@298: }
dvander@209: pPlugin->CancelMyCompile();
dvander@209: co = NULL;
dvander@209: break;
dvander@209: }
dvander@209: }
dvander@190: }
dvander@190: }
dvander@209:
dvander@298: /* Do the actual compiling */
dvander@209: if (co)
dvander@209: {
dvander@803: pPlugin->FinishMyCompile(error, maxlength);
dvander@209: co = NULL;
dvander@209: }
dvander@209:
dvander@298: /* Get the status */
dvander@211: if (pPlugin->GetStatus() == Plugin_Created)
dvander@211: {
dvander@211: AddCoreNativesToPlugin(pPlugin);
dvander@229: pPlugin->InitIdentity();
ds@755: if (pPlugin->Call_AskPluginLoad(error, maxlength))
dvander@315: {
dvander@315: /* Autoload any modules */
ds@755: LoadOrRequireExtensions(pPlugin, 1, error, maxlength);
teame06@1200: } else {
teame06@1200: pPlugin->SetErrorState(Plugin_Failed, "%s", error);
dvander@315: }
dvander@211: }
dvander@211:
faluco@333: /* Save the time stamp */
faluco@333: time_t t = pPlugin->GetFileTimeStamp();
faluco@333: pPlugin->SetTimeStamp(t);
faluco@333:
dvander@298: if (_plugin)
dvander@298: {
dvander@298: *_plugin = pPlugin;
dvander@298: }
dvander@298:
faluco@383: return (pPlugin->GetStatus() == Plugin_Loaded) ? LoadRes_Successful : LoadRes_Failure;
dvander@190: }
dvander@190:
ds@755: IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType type, char error[], size_t maxlength, bool *wasloaded)
dvander@174: {
dvander@298: CPlugin *pl;
faluco@383: LoadRes res;
dvander@211:
faluco@383: *wasloaded = false;
ds@755: if ((res=_LoadPlugin(&pl, path, debug, type, error, maxlength)) == LoadRes_Failure)
dvander@211: {
dvander@298: delete pl;
dvander@174: return NULL;
dvander@174: }
dvander@174:
faluco@383: if (res == LoadRes_AlreadyLoaded)
faluco@383: {
faluco@383: *wasloaded = true;
faluco@383: return pl;
faluco@383: }
faluco@383:
dvander@1436: if (res == LoadRes_NeverLoad)
dvander@1436: {
dvander@1436: UTIL_Format(error, maxlength, "This plugin is blocked from loading (see plugin_settings.cfg)");
dvander@1436: return NULL;
dvander@1436: }
dvander@1436:
dvander@298: AddPlugin(pl);
dvander@298:
dvander@315: /* Run second pass if we need to */
dvander@315: if (IsLateLoadTime() && pl->GetStatus() == Plugin_Loaded)
dvander@315: {
ds@755: if (!RunSecondPass(pl, error, maxlength))
dvander@315: {
dvander@315: UnloadPlugin(pl);
dvander@315: return NULL;
dvander@315: }
faluco@1221: pl->Call_OnAllPluginsLoaded();
dvander@315: }
dvander@315:
dvander@298: return pl;
dvander@298: }
dvander@298:
dvander@298: void CPluginManager::LoadAutoPlugin(const char *plugin)
dvander@298: {
dvander@1436: CPlugin *pl = NULL;
faluco@383: LoadRes res;
dvander@298: char error[255] = "Unknown error";
dvander@298:
faluco@383: if ((res=_LoadPlugin(&pl, plugin, false, PluginType_MapUpdated, error, sizeof(error))) == LoadRes_Failure)
dvander@209: {
dvander@305: g_Logger.LogError("[SM] Failed to load plugin \"%s\": %s", plugin, error);
dvander@298: pl->SetErrorState(Plugin_Failed, "%s", error);
dvander@209: }
dvander@209:
faluco@383: if (res == LoadRes_Successful)
faluco@383: {
faluco@383: AddPlugin(pl);
faluco@383: }
dvander@209: }
dvander@209:
dvander@211: void CPluginManager::AddPlugin(CPlugin *pPlugin)
dvander@209: {
dvander@174: List::iterator iter;
dvander@174: IPluginsListener *pListener;
dvander@298:
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@298: m_plugins.push_back(pPlugin);
dvander@298: sm_trie_insert(m_LoadLookup, pPlugin->m_filename, pPlugin);
dvander@211: }
dvander@211:
dvander@213: void CPluginManager::LoadAll_SecondPass()
dvander@213: {
dvander@213: List::iterator iter;
dvander@213: CPlugin *pPlugin;
dvander@213:
dvander@315: char error[256];
dvander@213: for (iter=m_plugins.begin(); iter!=m_plugins.end(); iter++)
dvander@213: {
dvander@213: pPlugin = (*iter);
dvander@213: if (pPlugin->GetStatus() == Plugin_Loaded)
dvander@213: {
dvander@315: error[0] = '\0';
dvander@315: if (!RunSecondPass(pPlugin, error, sizeof(error)))
dvander@315: {
dvander@315: g_Logger.LogError("[SM] Unable to load plugin \"%s\": %s", pPlugin->GetFilename(), error);
dvander@315: pPlugin->SetErrorState(Plugin_Failed, "%s", error);
dvander@315: }
dvander@213: }
dvander@213: }
dvander@298:
faluco@216: m_AllPluginsLoaded = true;
dvander@213: }
dvander@213:
faluco@1112: bool CPluginManager::FindOrRequirePluginDeps(CPlugin *pPlugin, char *error, size_t maxlength)
faluco@1112: {
faluco@1112: struct _pl
faluco@1112: {
faluco@1112: cell_t name;
faluco@1112: cell_t file;
faluco@1112: cell_t required;
faluco@1112: } *pl;
faluco@1112:
faluco@1112: IPluginContext *pBase = pPlugin->GetBaseContext();
faluco@1112: uint32_t num = pBase->GetPubVarsNum();
faluco@1112: sp_pubvar_t *pubvar;
faluco@1112: char *name, *file;
faluco@1112: char pathfile[PLATFORM_MAX_PATH];
faluco@1112:
faluco@1112: for (uint32_t i=0; iGetPubvarByIndex(i, &pubvar) != SP_ERROR_NONE)
faluco@1112: {
faluco@1112: continue;
faluco@1112: }
faluco@1112: if (strncmp(pubvar->name, "__pl_", 5) == 0)
faluco@1112: {
faluco@1112: pl = (_pl *)pubvar->offs;
faluco@1112: if (pBase->LocalToString(pl->file, &file) != SP_ERROR_NONE)
faluco@1112: {
faluco@1112: continue;
faluco@1112: }
faluco@1112: if (pBase->LocalToString(pl->name, &name) != SP_ERROR_NONE)
faluco@1112: {
faluco@1112: continue;
faluco@1112: }
faluco@1112: g_LibSys.GetFileFromPath(pathfile, sizeof(pathfile), pPlugin->GetFilename());
faluco@1112: if (strcmp(pathfile, file) == 0)
faluco@1112: {
faluco@1112: continue;
faluco@1112: }
faluco@1112: if (pl->required == false)
faluco@1112: {
faluco@1112: IPluginFunction *pFunc;
faluco@1112: char buffer[64];
dvander@1123: UTIL_Format(buffer, sizeof(buffer), "__pl_%s_SetNTVOptional", &pubvar->name[5]);
faluco@1112: if ((pFunc=pBase->GetFunctionByName(buffer)))
faluco@1112: {
faluco@1112: cell_t res;
faluco@1112: pFunc->Execute(&res);
faluco@1112: if (pPlugin->GetContext()->n_err != SP_ERROR_NONE)
faluco@1112: {
faluco@1112: if (error)
faluco@1112: {
faluco@1112: snprintf(error, maxlength, "Fatal error during initializing plugin load");
faluco@1112: }
faluco@1112: return false;
faluco@1112: }
faluco@1112: }
faluco@1112: } else {
faluco@1112: /* Check that we aren't registering the same library twice */
faluco@1112: if (pPlugin->m_RequiredLibs.find(name) == pPlugin->m_RequiredLibs.end())
faluco@1112: {
faluco@1112: pPlugin->m_RequiredLibs.push_back(name);
faluco@1112: } else {
faluco@1112: continue;
faluco@1112: }
faluco@1112: List::iterator iter;
faluco@1112: CPlugin *pl;
faluco@1112: bool found = false;
faluco@1112: for (iter=m_plugins.begin(); iter!=m_plugins.end(); iter++)
faluco@1112: {
faluco@1112: pl = (*iter);
faluco@1112: if (pl->m_Libraries.find(name) != pl->m_Libraries.end())
faluco@1112: {
faluco@1112: found = true;
faluco@1112: break;
faluco@1112: }
faluco@1112: }
faluco@1112: if (!found)
faluco@1112: {
faluco@1112: if (error)
faluco@1112: {
faluco@1112: snprintf(error, maxlength, "Could not find required plugin \"%s\"", name);
faluco@1112: }
faluco@1112: return false;
faluco@1112: }
faluco@1112: }
faluco@1112: }
faluco@1112: }
faluco@1112:
faluco@1112: return true;
faluco@1112: }
faluco@1112:
dvander@315: bool CPluginManager::LoadOrRequireExtensions(CPlugin *pPlugin, unsigned int pass, char *error, size_t maxlength)
dvander@211: {
dvander@298: /* Find any extensions this plugin needs */
dvander@298: struct _ext
dvander@298: {
dvander@298: cell_t name;
dvander@298: cell_t file;
dvander@298: cell_t autoload;
dvander@298: cell_t required;
dvander@298: } *ext;
dvander@298:
dvander@298: IPluginContext *pBase = pPlugin->GetBaseContext();
dvander@298: uint32_t num = pBase->GetPubVarsNum();
dvander@298: sp_pubvar_t *pubvar;
dvander@298: IExtension *pExt;
ds@652: char path[PLATFORM_MAX_PATH];
dvander@298: char *file, *name;
dvander@298: for (uint32_t i=0; iGetPubvarByIndex(i, &pubvar) != SP_ERROR_NONE)
dvander@298: {
dvander@298: continue;
dvander@298: }
dvander@298: if (strncmp(pubvar->name, "__ext_", 6) == 0)
dvander@298: {
dvander@298: ext = (_ext *)pubvar->offs;
dvander@298: if (!ext->required && !ext->autoload)
dvander@298: {
dvander@298: continue;
dvander@298: }
dvander@298: if (pBase->LocalToString(ext->file, &file) != SP_ERROR_NONE)
dvander@298: {
dvander@298: continue;
dvander@298: }
dvander@298: if (pBase->LocalToString(ext->name, &name) != SP_ERROR_NONE)
dvander@298: {
dvander@298: continue;
dvander@298: }
dvander@315: if (pass == 1)
dvander@298: {
dvander@315: /* Attempt to auto-load if necessary */
dvander@315: if (ext->autoload)
dvander@315: {
dvander@315: g_LibSys.PathFormat(path, PLATFORM_MAX_PATH, "%s", file);
dvander@315: g_Extensions.LoadAutoExtension(path);
dvander@315: }
dvander@315: } else if (pass == 2) {
dvander@315: /* Is this required? */
dvander@315: if (ext->required)
dvander@298: {
dvander@315: g_LibSys.PathFormat(path, PLATFORM_MAX_PATH, "%s", file);
dvander@315: if ((pExt = g_Extensions.FindExtensionByFile(path)) == NULL)
dvander@315: {
dvander@315: pExt = g_Extensions.FindExtensionByName(name);
dvander@315: }
dvander@315: /* :TODO: should we bind to unloaded extensions?
dvander@315: * Currently the extension manager will ignore this.
dvander@315: */
dvander@315: if (!pExt || !pExt->IsRunning(NULL, 0))
dvander@315: {
dvander@315: if (error)
dvander@315: {
dvander@315: snprintf(error, maxlength, "Required extension \"%s\" file(\"%s\") not running", name, file);
dvander@315: }
dvander@315: return false;
dvander@315: } else {
dvander@315: g_Extensions.BindChildPlugin(pExt, pPlugin);
dvander@315: }
dvander@298: }
dvander@298: }
dvander@315: }
dvander@315: }
dvander@315:
dvander@315: return true;
dvander@315: }
dvander@315:
dvander@315: bool CPluginManager::RunSecondPass(CPlugin *pPlugin, char *error, size_t maxlength)
dvander@315: {
dvander@315: /* Second pass for extension requirements */
dvander@315: if (!LoadOrRequireExtensions(pPlugin, 2, error, maxlength))
dvander@315: {
dvander@315: return false;
dvander@315: }
dvander@315:
dvander@315: /* Bind all extra natives */
dvander@315: g_Extensions.BindAllNativesToPlugin(pPlugin);
dvander@601: AddFakeNativesToPlugin(pPlugin);
dvander@315:
faluco@1112: if (!FindOrRequirePluginDeps(pPlugin, error, maxlength))
faluco@1112: {
faluco@1112: return false;
faluco@1112: }
faluco@1112:
dvander@315: /* Find any unbound natives
dvander@315: * Right now, these are not allowed
dvander@315: */
dvander@315: IPluginContext *pContext = pPlugin->GetBaseContext();
dvander@315: uint32_t num = pContext->GetNativesNum();
dvander@315: sp_native_t *native;
dvander@315: for (unsigned int i=0; iGetNativeByIndex(i, &native) != SP_ERROR_NONE)
dvander@315: {
dvander@315: break;
dvander@315: }
dvander@798: if (native->status == SP_NATIVE_UNBOUND
faluco@1089: && native->name[0] != '@'
faluco@1089: && !(native->flags & SP_NTVFLAG_OPTIONAL))
dvander@315: {
dvander@315: if (error)
dvander@298: {
dvander@315: snprintf(error, maxlength, "Native \"%s\" was not found.", native->name);
dvander@298: }
dvander@315: return false;
dvander@298: }
dvander@298: }
dvander@211:
dvander@211: /* Finish by telling all listeners */
dvander@211: List::iterator iter;
dvander@211: IPluginsListener *pListener;
dvander@211: for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++)
dvander@211: {
dvander@211: pListener = (*iter);
dvander@211: pListener->OnPluginLoaded(pPlugin);
dvander@211: }
dvander@298:
dvander@298: /* Tell this plugin to finish initializing itself */
ds@426: pPlugin->Call_OnPluginStart();
dvander@298:
dvander@605: /* Now, if we have fake natives, go through all plugins that might need rebinding */
dvander@1122: if (pPlugin->GetStatus() <= Plugin_Paused && pPlugin->m_fakeNatives.size())
dvander@605: {
dvander@605: List::iterator pl_iter;
dvander@605: CPlugin *pOther;
dvander@605: for (pl_iter = m_plugins.begin();
dvander@605: pl_iter != m_plugins.end();
dvander@605: pl_iter++)
dvander@605: {
dvander@605: pOther = (*pl_iter);
dvander@1122: if ((pOther->GetStatus() == Plugin_Error
faluco@1112: && (pOther->m_FakeNativesMissing || pOther->m_LibraryMissing))
dvander@1122: || pOther->m_FakeNativesMissing)
dvander@605: {
faluco@1112: TryRefreshDependencies(pOther);
dvander@605: }
dvander@605: }
dvander@605: }
dvander@605:
dvander@1124: /* Go through our libraries and tell other plugins they're added */
dvander@1124: List::iterator s_iter;
dvander@1124: for (s_iter = pPlugin->m_Libraries.begin();
dvander@1124: s_iter != pPlugin->m_Libraries.end();
dvander@1124: s_iter++)
dvander@1124: {
dvander@1124: OnLibraryAction((*s_iter).c_str(), false);
dvander@1124: }
dvander@1124:
dvander@298: return true;
dvander@211: }
dvander@211:
dvander@211: void CPluginManager::AddCoreNativesToPlugin(CPlugin *pPlugin)
dvander@211: {
dvander@1382: IPluginContext *pContext = pPlugin->GetBaseContext();
dvander@1382:
dvander@211:
dvander@1382: uint32_t natives = pContext->GetNativesNum();
dvander@1382: sp_native_t *native;
dvander@1382: SPVM_NATIVE_FUNC pfn;
dvander@1382: for (uint32_t i=0; iGetNativeByIndex(i, &native) != SP_ERROR_NONE)
dvander@1382: {
dvander@1382: continue;
dvander@1382: }
dvander@1382: if (native->status == SP_NATIVE_BOUND)
dvander@211: {
dvander@1382: continue;
dvander@211: }
dvander@1382: if (!sm_trie_retrieve(m_pCoreNatives, native->name, (void **)&pfn))
dvander@1382: {
dvander@1382: continue;
dvander@1382: }
dvander@1382: pContext->BindNativeToIndex(i, pfn);
dvander@211: }
dvander@174: }
dvander@174:
faluco@1112: void CPluginManager::TryRefreshDependencies(CPlugin *pPlugin)
dvander@605: {
dvander@605: assert(pPlugin->GetBaseContext() != NULL);
dvander@605:
dvander@605: AddFakeNativesToPlugin(pPlugin);
dvander@605:
faluco@1112: List::iterator lib_iter;
faluco@1112: List::iterator req_iter;
faluco@1112: List::iterator pl_iter;
faluco@1112: CPlugin *pl;
faluco@1112: for (req_iter=pPlugin->m_RequiredLibs.begin(); req_iter!=pPlugin->m_RequiredLibs.end(); req_iter++)
faluco@1112: {
faluco@1112: bool found = false;
faluco@1112: for (pl_iter=m_plugins.begin(); pl_iter!=m_plugins.end(); pl_iter++)
faluco@1112: {
faluco@1112: pl = (*pl_iter);
faluco@1112: for (lib_iter=pl->m_Libraries.begin(); lib_iter!=pl->m_Libraries.end(); lib_iter++)
faluco@1112: {
faluco@1112: if ((*req_iter) == (*lib_iter))
faluco@1112: {
faluco@1112: found = true;
faluco@1112: }
faluco@1112: }
faluco@1112: }
faluco@1112: if (!found)
faluco@1112: {
faluco@1112: pPlugin->SetErrorState(Plugin_Error, "Library not found: %s", (*req_iter).c_str());
faluco@1112: return;
faluco@1112: }
faluco@1112: }
faluco@1112:
dvander@605: /* Find any unbound natives
dvander@605: * Right now, these are not allowed
dvander@605: */
dvander@605: IPluginContext *pContext = pPlugin->GetBaseContext();
dvander@605: uint32_t num = pContext->GetNativesNum();
dvander@605: sp_native_t *native;
dvander@605: for (unsigned int i=0; iGetNativeByIndex(i, &native) != SP_ERROR_NONE)
dvander@605: {
dvander@605: break;
dvander@605: }
faluco@1089: if (native->status == SP_NATIVE_UNBOUND && !(native->flags & SP_NTVFLAG_OPTIONAL))
dvander@605: {
dvander@605: pPlugin->SetErrorState(Plugin_Error, "Native not found: %s", native->name);
dvander@605: return;
dvander@605: }
dvander@605: }
dvander@605:
dvander@1122: if (pPlugin->GetStatus() == Plugin_Error)
dvander@605: {
dvander@1122: /* If we got here, all natives are okay again! */
dvander@1122: pPlugin->m_status = Plugin_Running;
dvander@1122: if ((pPlugin->m_ctx.ctx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED)
dvander@1122: {
dvander@1122: pPlugin->m_ctx.ctx->flags &= ~SPFLAG_PLUGIN_PAUSED;
dvander@1122: _SetPauseState(pPlugin, false);
dvander@1122: }
dvander@605: }
dvander@605: }
dvander@605:
dvander@601: void CPluginManager::AddFakeNativesToPlugin(CPlugin *pPlugin)
dvander@601: {
dvander@601: IPluginContext *pContext = pPlugin->GetBaseContext();
dvander@601: sp_nativeinfo_t native;
dvander@601:
dvander@601: List::iterator iter;
dvander@601: FakeNative *pNative;
dvander@601: sp_context_t *ctx;
dvander@601: for (iter = m_Natives.begin(); iter != m_Natives.end(); iter++)
dvander@601: {
dvander@601: pNative = (*iter);
dvander@601: ctx = pNative->ctx->GetContext();
dvander@601: if ((ctx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED)
dvander@601: {
dvander@601: /* Ignore natives in paused plugins */
dvander@601: continue;
dvander@601: }
dvander@601: native.name = pNative->name.c_str();
dvander@601: native.func = pNative->func;
dvander@601: if (pContext->BindNative(&native) == SP_ERROR_NONE)
dvander@601: {
faluco@1089: uint32_t idx;
faluco@1089: pContext->FindNativeByName(native.name, &idx);
faluco@1112: if (pPlugin->GetContext()->natives[idx].flags & SP_NTVFLAG_OPTIONAL)
faluco@1089: {
dvander@1122: WeakNative wkn(pPlugin, idx);
faluco@1112: GetPluginByCtx(ctx)->m_WeakNatives.push_back(wkn);
faluco@1089: continue;
faluco@1089: }
dvander@605: /* Add us as a dependency, but we're careful not to do this circularly! */
dvander@605: if (pNative->ctx != pContext)
dvander@605: {
dvander@605: CPlugin *pOther = GetPluginByCtx(ctx);
dvander@605: if (pOther->m_dependents.find(pPlugin) == pOther->m_dependents.end())
dvander@605: {
dvander@605: pOther->m_dependents.push_back(pPlugin);
dvander@605: }
dvander@605: if (pPlugin->m_dependsOn.find(pOther) == pPlugin->m_dependsOn.end())
dvander@605: {
dvander@605: pPlugin->m_dependsOn.push_back(pOther);
dvander@605: }
dvander@605: }
dvander@601: }
dvander@601: }
dvander@601: }
dvander@601:
dvander@174: bool CPluginManager::UnloadPlugin(IPlugin *plugin)
dvander@174: {
dvander@174: CPlugin *pPlugin = (CPlugin *)plugin;
dvander@298:
dvander@298: /* This prevents removal during insertion or anything else weird */
dvander@298: if (m_plugins.find(pPlugin) == m_plugins.end())
dvander@298: {
dvander@298: return false;
dvander@298: }
dvander@298:
dvander@605: /* Remove us from the lookup table and linked list */
dvander@605: m_plugins.remove(pPlugin);
dvander@605: sm_trie_delete(m_LoadLookup, pPlugin->m_filename);
dvander@605:
dvander@1124: /* Go through our libraries and tell other plugins they're gone */
dvander@1124: List::iterator s_iter;
dvander@1124: for (s_iter = pPlugin->m_Libraries.begin();
dvander@1124: s_iter != pPlugin->m_Libraries.end();
dvander@1124: s_iter++)
dvander@1124: {
dvander@1124: OnLibraryAction((*s_iter).c_str(), true);
dvander@1124: }
dvander@1124:
dvander@605: /* Go through all dependent plugins and tell them this plugin is now gone */
dvander@605: List::iterator pl_iter;
dvander@605: CPlugin *pOther;
dvander@605: for (pl_iter = pPlugin->m_dependents.begin();
dvander@605: pl_iter != pPlugin->m_dependents.end();
dvander@605: pl_iter++)
dvander@605: {
dvander@605: pOther = (*pl_iter);
dvander@605: pOther->DependencyDropped(pPlugin);
dvander@605: }
dvander@605:
dvander@605: /* Tell everyone we depend on that we no longer exist */
dvander@605: for (pl_iter = pPlugin->m_dependsOn.begin();
dvander@605: pl_iter != pPlugin->m_dependsOn.end();
dvander@605: pl_iter++)
dvander@605: {
dvander@605: pOther = (*pl_iter);
dvander@605: pOther->m_dependents.remove(pPlugin);
dvander@605: }
dvander@605:
dvander@1122: /* Remove weak references to us */
dvander@1122: for (pl_iter = m_plugins.begin();
dvander@1122: pl_iter != m_plugins.end();
dvander@1122: pl_iter++)
dvander@1122: {
dvander@1122: pOther = (*pl_iter);
dvander@1122: List::iterator wk_iter = pOther->m_WeakNatives.begin();
dvander@1122: while (wk_iter != pOther->m_WeakNatives.end())
dvander@1122: {
dvander@1122: if ((*wk_iter).pl == pPlugin)
dvander@1122: {
dvander@1122: wk_iter = pOther->m_WeakNatives.erase(wk_iter);
dvander@1122: } else {
dvander@1122: wk_iter++;
dvander@1122: }
dvander@1122: }
dvander@1122: }
dvander@1122:
dvander@174: List::iterator iter;
dvander@174: IPluginsListener *pListener;
dvander@282:
dvander@311: if (pPlugin->GetStatus() <= Plugin_Error)
dvander@282: {
dvander@282: /* Notify listeners of unloading */
dvander@282: for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++)
dvander@282: {
dvander@282: pListener = (*iter);
dvander@282: pListener->OnPluginUnloaded(pPlugin);
dvander@282: }
dvander@282: /* Notify plugin */
ds@426: pPlugin->Call_OnPluginEnd();
dvander@282: }
dvander@282:
dvander@1122: /* Unbound weak natives */
dvander@1122: List::iterator wk_iter;
dvander@1122: for (wk_iter=pPlugin->m_WeakNatives.begin(); wk_iter!=pPlugin->m_WeakNatives.end(); wk_iter++)
dvander@1122: {
dvander@1122: WeakNative & wkn = (*wk_iter);
dvander@1122: sp_context_t *ctx = wkn.pl->GetContext();
dvander@1122: ctx->natives[wkn.idx].status = SP_NATIVE_UNBOUND;
dvander@1122: wkn.pl->m_FakeNativesMissing = true;
dvander@1122: }
dvander@1122:
faluco@1112: /* Remove all of our native functions */
faluco@1112: List::iterator fn_iter;
faluco@1112: FakeNative *pNative;
faluco@1112: for (fn_iter = pPlugin->m_fakeNatives.begin();
faluco@1112: fn_iter != pPlugin->m_fakeNatives.end();
faluco@1112: fn_iter++)
faluco@1112: {
faluco@1112: pNative = (*fn_iter);
faluco@1112: m_Natives.remove(pNative);
faluco@1112: sm_trie_delete(m_pNativeLookup, pNative->name.c_str());
faluco@1112: g_pVM->DestroyFakeNative(pNative->func);
faluco@1112: delete pNative;
faluco@1112: }
faluco@1112:
dvander@174: for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++)
dvander@174: {
dvander@282: /* Notify listeners of destruction */
dvander@174: pListener = (*iter);
dvander@174: pListener->OnPluginDestroyed(pPlugin);
dvander@174: }
dvander@176:
dvander@282: /* Tell the plugin to delete itself */
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();
faluco@216: iter->Reset();
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@203: bool CPluginManager::TestAliasMatch(const char *alias, const char *localpath)
dvander@203: {
dvander@203: /* As an optimization, we do not call strlen, but compute the length in the first pass */
dvander@203: size_t alias_len = 0;
dvander@203: size_t local_len = 0;
dvander@203:
dvander@203: const char *ptr = alias;
dvander@203: unsigned int alias_explicit_paths = 0;
dvander@203: unsigned int alias_path_end = 0;
dvander@203: while (*ptr != '\0')
dvander@203: {
dvander@203: if (*ptr == '\\' || *ptr == '/')
dvander@203: {
dvander@203: alias_explicit_paths++;
dvander@203: alias_path_end = alias_len;
dvander@203: }
dvander@203: alias_len++;
dvander@203: ptr++;
dvander@203: }
dvander@203:
dvander@209: if (alias_explicit_paths && alias_path_end == alias_len - 1)
dvander@203: {
dvander@203: /* Trailing slash is totally invalid here */
dvander@203: return false;
dvander@203: }
dvander@203:
dvander@203: ptr = localpath;
dvander@203: unsigned int local_explicit_paths = 0;
dvander@203: unsigned int local_path_end = 0;
dvander@203: while (*ptr != '\0')
dvander@203: {
dvander@203: if (*ptr == '\\' || *ptr == '/')
dvander@203: {
dvander@203: local_explicit_paths++;
dvander@203: local_path_end = local_len;
dvander@203: }
dvander@203: local_len++;
dvander@203: ptr++;
dvander@203: }
dvander@203:
dvander@203: /* If the alias has more explicit paths than the real path,
dvander@203: * no match will be possible.
dvander@203: */
dvander@203: if (alias_explicit_paths > local_explicit_paths)
dvander@203: {
dvander@203: return false;
dvander@203: }
dvander@203:
dvander@203: if (alias_explicit_paths)
dvander@203: {
dvander@203: /* We need to find if the paths match now. For example, these should all match:
dvander@203: * csdm csdm
dvander@203: * csdm optional/csdm
dvander@203: * csdm/ban optional/crab/csdm/ban
dvander@203: */
dvander@203: const char *aliasptr = alias;
dvander@203: const char *localptr = localpath;
dvander@203: bool match = true;
dvander@203: do
dvander@203: {
dvander@203: if (*aliasptr != *localptr)
dvander@203: {
dvander@203: /* We have to knock one path off */
dvander@203: local_explicit_paths--;
dvander@203: if (alias_explicit_paths > local_explicit_paths)
dvander@203: {
dvander@203: /* Skip out if we're gonna have an impossible match */
dvander@203: return false;
dvander@203: }
dvander@203: /* Eat up localptr tokens until we get a result */
dvander@203: while (((localptr - localpath) < (int)local_path_end)
dvander@203: && *localptr != '/'
dvander@203: && *localptr != '\\')
dvander@203: {
dvander@203: localptr++;
dvander@203: }
dvander@203: /* Check if we hit the end of our searchable area.
dvander@203: * This probably isn't possible because of the path
dvander@203: * count check, but it's a good idea anyway.
dvander@203: */
dvander@203: if ((localptr - localpath) >= (int)local_path_end)
dvander@203: {
dvander@203: return false;
dvander@203: } else {
dvander@203: /* Consume the slash token */
dvander@203: localptr++;
dvander@203: }
dvander@203: /* Reset the alias pointer so we can continue consuming */
dvander@203: aliasptr = alias;
dvander@203: match = false;
dvander@203: continue;
dvander@203: }
dvander@203: /* Note:
dvander@203: * This is safe because if localptr terminates early, aliasptr will too
dvander@203: */
dvander@203: do
dvander@203: {
dvander@203: /* We should never reach the end of the string because of this check. */
dvander@203: bool aliasend = (aliasptr - alias) > (int)alias_path_end;
dvander@203: bool localend = (localptr - localpath) > (int)local_path_end;
dvander@203: if (aliasend || localend)
dvander@203: {
dvander@203: if (aliasend && localend)
dvander@203: {
dvander@203: /* we matched, and we can break out now */
dvander@203: match = true;
dvander@203: break;
dvander@203: }
dvander@203: /* Otherwise, we've hit the end somehow and rest won't match up. Break out. */
dvander@203: match = false;
dvander@203: break;
dvander@203: }
dvander@203:
dvander@203: /* If we got here, it's safe to compare the next two tokens */
dvander@203: if (*localptr != *aliasptr)
dvander@203: {
dvander@203: match = false;
dvander@203: break;
dvander@203: }
dvander@203: localptr++;
dvander@203: aliasptr++;
dvander@203: } while (true);
dvander@203: } while (!match);
dvander@203: }
dvander@203:
dvander@203: /* If we got here, it's time to compare filenames */
dvander@203: const char *aliasptr = alias;
dvander@203: const char *localptr = localpath;
dvander@203:
dvander@203: if (alias_explicit_paths)
dvander@203: {
dvander@203: aliasptr = &alias[alias_path_end + 1];
dvander@203: }
dvander@203:
dvander@203: if (local_explicit_paths)
dvander@203: {
dvander@203: localptr = &localpath[local_path_end + 1];
dvander@203: }
dvander@203:
dvander@203: while (true)
dvander@203: {
dvander@203: if (*aliasptr == '*')
dvander@203: {
dvander@203: /* First, see if this is the last character */
dvander@351: if ((unsigned)(aliasptr - alias) == alias_len - 1)
dvander@203: {
dvander@203: /* If so, there's no need to match anything else */
dvander@203: return true;
dvander@203: }
dvander@203: /* Otherwise, we need to search for an appropriate matching sequence in local.
dvander@203: * Note that we only need to search up to the next asterisk.
dvander@203: */
dvander@203: aliasptr++;
dvander@203: bool match = true;
dvander@203: const char *local_orig = localptr;
dvander@203: do
dvander@203: {
dvander@203: match = true;
dvander@203: while (*aliasptr != '\0' && *aliasptr != '*')
dvander@203: {
dvander@203: /* Since aliasptr is never '\0', localptr hitting the end will fail */
dvander@203: if (*aliasptr != *localptr)
dvander@203: {
dvander@203: match = false;
dvander@203: break;
dvander@203: }
dvander@203: aliasptr++;
dvander@203: localptr++;
dvander@203: }
dvander@203: if (!match)
dvander@203: {
dvander@203: /* If we didn't get a match, we need to advance the search stream.
dvander@203: * This will let us skip tokens while still searching for another match.
dvander@203: */
dvander@203: localptr = ++local_orig;
dvander@203: /* Make sure we don't go out of bounds */
dvander@203: if (*localptr == '\0')
dvander@203: {
dvander@203: break;
dvander@203: }
dvander@203: }
dvander@203: } while (!match);
dvander@203:
dvander@203: if (!match)
dvander@203: {
dvander@203: return false;
dvander@203: } else {
dvander@203: /* If we got a match, move on to the next token */
dvander@203: continue;
dvander@203: }
dvander@203: } else if (*aliasptr == '\0') {
dvander@203: if (*localptr == '\0'
dvander@203: ||
dvander@203: strcmp(localptr, ".smx") == 0)
dvander@203: {
dvander@203: return true;
dvander@203: } else {
dvander@203: return false;
dvander@203: }
dvander@203: } else if (*aliasptr != *localptr) {
dvander@203: return false;
dvander@203: }
dvander@203: aliasptr++;
dvander@203: localptr++;
dvander@203: }
dvander@203:
dvander@203: return true;
dvander@203: }
dvander@203:
faluco@290: bool CPluginManager::IsLateLoadTime() const
dvander@176: {
dvander@315: return (m_AllPluginsLoaded || !g_SourceMod.IsMapLoading());
dvander@176: }
dvander@220:
dvander@220: void CPluginManager::OnSourceModAllInitialized()
dvander@220: {
dvander@229: m_MyIdent = g_ShareSys.CreateCoreIdentity();
dvander@229:
dvander@262: HandleAccess sec;
dvander@262: g_HandleSys.InitAccessDefaults(NULL, &sec);
dvander@220:
dvander@262: sec.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY;
dvander@262: sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY;
dvander@262:
dvander@262: g_PluginType = g_HandleSys.CreateType("Plugin", this, 0, NULL, &sec, m_MyIdent, NULL);
dvander@229: g_PluginIdent = g_ShareSys.CreateIdentType("PLUGIN");
dvander@309:
dvander@309: g_RootMenu.AddRootConsoleCommand("plugins", "Manage Plugins", this);
dvander@336:
dvander@336: g_ShareSys.AddInterface(NULL, this);
dvander@220: }
dvander@220:
dvander@220: void CPluginManager::OnSourceModShutdown()
dvander@220: {
dvander@309: g_RootMenu.RemoveRootConsoleCommand("plugins", this);
dvander@309:
dvander@298: List::iterator iter;
dvander@298: while ( (iter = m_plugins.begin()) != m_plugins.end() )
dvander@298: {
dvander@298: UnloadPlugin((*iter));
dvander@298: }
dvander@298:
dvander@229: g_HandleSys.RemoveType(g_PluginType, m_MyIdent);
dvander@229: g_ShareSys.DestroyIdentType(g_PluginIdent);
dvander@229: g_ShareSys.DestroyIdentity(m_MyIdent);
dvander@220: }
dvander@220:
dvander@220: void CPluginManager::OnHandleDestroy(HandleType_t type, void *object)
dvander@220: {
dvander@220: /* We don't care about the internal object, actually */
dvander@220: }
dvander@233:
dvander@233: void CPluginManager::RegisterNativesFromCore(sp_nativeinfo_t *natives)
dvander@233: {
dvander@1382: for (unsigned int i = 0; natives[i].func != NULL; i++)
dvander@1382: {
dvander@1388: sm_trie_insert(m_pCoreNatives, natives[i].name, (void *)natives[i].func);
dvander@1382: }
dvander@233: }
dvander@247:
dvander@247: IPlugin *CPluginManager::PluginFromHandle(Handle_t handle, HandleError *err)
dvander@247: {
dvander@247: IPlugin *pPlugin;
dvander@247: HandleError _err;
dvander@247:
dvander@262: HandleSecurity sec;
dvander@262:
dvander@262: sec.pOwner = NULL;
dvander@262: sec.pIdentity = m_MyIdent;
dvander@262:
dvander@262: if ((_err=g_HandleSys.ReadHandle(handle, g_PluginType, &sec, (void **)&pPlugin)) != HandleError_None)
dvander@247: {
dvander@247: pPlugin = NULL;
dvander@247: }
dvander@247:
dvander@247: if (err)
dvander@247: {
dvander@247: *err = _err;
dvander@247: }
dvander@247:
dvander@247: return pPlugin;
dvander@247: }
faluco@290:
faluco@290: CPlugin *CPluginManager::GetPluginByOrder(int num)
faluco@290: {
faluco@290: if (num < 1 || num > (int)GetPluginCount())
faluco@290: {
faluco@290: return NULL;
faluco@290: }
faluco@290:
faluco@290: CPlugin *pl;
faluco@290: int id = 1;
faluco@290:
faluco@290: IPluginIterator *iter = GetPluginIterator();
faluco@290: for (; iter->MorePlugins() && idNextPlugin(), id++) {}
faluco@290:
faluco@290: pl = (CPlugin *)(iter->GetPlugin());
faluco@290: iter->Release();
faluco@290:
faluco@290: return pl;
dvander@298: }
dvander@309:
dvander@309: const char *CPluginManager::GetStatusText(PluginStatus st)
dvander@309: {
dvander@309: switch (st)
dvander@309: {
dvander@309: case Plugin_Running:
dvander@309: return "Running";
dvander@309: case Plugin_Paused:
dvander@309: return "Paused";
dvander@309: case Plugin_Error:
dvander@309: return "Error";
dvander@309: case Plugin_Uncompiled:
dvander@309: return "Uncompiled";
dvander@309: case Plugin_BadLoad:
dvander@309: return "Bad Load";
dvander@309: case Plugin_Failed:
dvander@309: return "Failed";
dvander@309: default:
dvander@309: assert(false);
dvander@309: return "-";
dvander@309: }
dvander@309: }
dvander@309:
faluco@1541: void CPluginManager::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
dvander@309: {
faluco@1541: int argcount = command.ArgC();
dvander@309: if (argcount >= 3)
dvander@309: {
faluco@1541: const char *cmd = command.Arg(2);
dvander@309: if (strcmp(cmd, "list") == 0)
dvander@309: {
dvander@309: char buffer[256];
dvander@309: unsigned int id = 1;
dvander@309: int plnum = GetPluginCount();
dvander@309:
dvander@309: if (!plnum)
dvander@309: {
dvander@309: g_RootMenu.ConsolePrint("[SM] No plugins loaded");
dvander@309: return;
dvander@309: } else {
ds@582: g_RootMenu.ConsolePrint("[SM] Listing %d plugin%s:", GetPluginCount(), (plnum > 1) ? "s" : "");
dvander@309: }
dvander@309:
dvander@309: IPluginIterator *iter = GetPluginIterator();
dvander@309: for (; iter->MorePlugins(); iter->NextPlugin(), id++)
dvander@309: {
dvander@309: IPlugin *pl = iter->GetPlugin();
dvander@309: assert(pl->GetStatus() != Plugin_Created);
dvander@309: int len = 0;
dvander@309: const sm_plugininfo_t *info = pl->GetPublicInfo();
dvander@351: if (pl->GetStatus() != Plugin_Running)
dvander@340: {
dvander@340: len += UTIL_Format(buffer, sizeof(buffer), " %02d <%s>", id, GetStatusText(pl->GetStatus()));
dvander@340: } else {
dvander@340: len += UTIL_Format(buffer, sizeof(buffer), " %02d", id);
dvander@340: }
dvander@309: len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " \"%s\"", (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename());
dvander@309: if (IS_STR_FILLED(info->version))
dvander@309: {
dvander@309: len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " (%s)", info->version);
dvander@309: }
dvander@309: if (IS_STR_FILLED(info->author))
dvander@309: {
dvander@309: UTIL_Format(&buffer[len], sizeof(buffer)-len, " by %s", info->author);
dvander@309: }
dvander@309: g_RootMenu.ConsolePrint("%s", buffer);
dvander@309: }
dvander@309:
dvander@309: iter->Release();
dvander@309: return;
dvander@309: } else if (strcmp(cmd, "load") == 0) {
dvander@309: if (argcount < 4)
dvander@309: {
dvander@310: g_RootMenu.ConsolePrint("[SM] Usage: sm plugins load ");
dvander@309: return;
dvander@309: }
dvander@309:
dvander@309: char error[128];
faluco@383: bool wasloaded;
faluco@1541: const char *filename = command.Arg(3);
ds@794:
ds@794: char pluginfile[256];
ds@794: const char *ext = g_LibSys.GetFileExtension(filename) ? "" : ".smx";
ds@794: UTIL_Format(pluginfile, sizeof(pluginfile), "%s%s", filename, ext);
ds@794:
ds@794: IPlugin *pl = LoadPlugin(pluginfile, false, PluginType_MapUpdated, error, sizeof(error), &wasloaded);
faluco@383:
faluco@383: if (wasloaded)
faluco@383: {
ds@794: g_RootMenu.ConsolePrint("[SM] Plugin %s is already loaded.", pluginfile);
faluco@383: return;
faluco@383: }
dvander@309:
dvander@309: if (pl)
dvander@309: {
ds@794: g_RootMenu.ConsolePrint("[SM] Loaded plugin %s successfully.", pluginfile);
dvander@309: } else {
ds@794: g_RootMenu.ConsolePrint("[SM] Plugin %s failed to load: %s.", pluginfile, error);
dvander@309: }
dvander@309:
dvander@309: return;
dvander@309: } else if (strcmp(cmd, "unload") == 0) {
dvander@309: if (argcount < 4)
dvander@309: {
ds@1252: g_RootMenu.ConsolePrint("[SM] Usage: sm plugins unload <#|file>");
dvander@309: return;
dvander@309: }
dvander@309:
ds@1252: CPlugin *pl;
ds@1252: char *end;
faluco@1541: const char *arg = command.Arg(3);
ds@1252: int id = strtol(arg, &end, 10);
ds@1252:
ds@1252: if (*end == '\0')
dvander@309: {
ds@1252: pl = GetPluginByOrder(id);
ds@1252: if (!pl)
ds@1252: {
ds@1252: g_RootMenu.ConsolePrint("[SM] Plugin index %d not found.", id);
ds@1252: return;
ds@1252: }
ds@1252: } else {
ds@1252: char pluginfile[256];
ds@1252: const char *ext = g_LibSys.GetFileExtension(arg) ? "" : ".smx";
ds@1252: UTIL_Format(pluginfile, sizeof(pluginfile), "%s%s", arg, ext);
dvander@309:
ds@1252: if (!sm_trie_retrieve(m_LoadLookup, pluginfile, (void **)&pl))
ds@1252: {
ds@1252: g_RootMenu.ConsolePrint("[SM] Plugin %s is not loaded.", pluginfile);
ds@1252: return;
ds@1252: }
ds@1252: }
dvander@309:
ds@652: char name[PLATFORM_MAX_PATH];
dvander@309: const sm_plugininfo_t *info = pl->GetPublicInfo();
dvander@309: strcpy(name, (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename());
dvander@309:
dvander@309: if (UnloadPlugin(pl))
dvander@309: {
dvander@310: g_RootMenu.ConsolePrint("[SM] Plugin %s unloaded successfully.", name);
dvander@309: } else {
dvander@310: g_RootMenu.ConsolePrint("[SM] Failed to unload plugin %s.", name);
dvander@309: }
dvander@309:
dvander@309: return;
dvander@309: } else if (strcmp(cmd, "info") == 0) {
dvander@309: if (argcount < 4)
dvander@309: {
dvander@310: g_RootMenu.ConsolePrint("[SM] Usage: sm plugins info <#>");
dvander@309: return;
dvander@309: }
dvander@309:
faluco@1541: int num = atoi(command.Arg(3));
dvander@309: if (num < 1 || num > (int)GetPluginCount())
dvander@309: {
dvander@310: g_RootMenu.ConsolePrint("[SM] Plugin index not found.");
dvander@309: return;
dvander@309: }
dvander@309:
dvander@315: CPlugin *pl = GetPluginByOrder(num);
dvander@309: const sm_plugininfo_t *info = pl->GetPublicInfo();
dvander@309:
dvander@309: g_RootMenu.ConsolePrint(" Filename: %s", pl->GetFilename());
dvander@315: if (pl->GetStatus() <= Plugin_Error)
dvander@309: {
dvander@315: if (IS_STR_FILLED(info->name))
dvander@315: {
dvander@605: if (IS_STR_FILLED(info->description))
dvander@605: {
dvander@605: g_RootMenu.ConsolePrint(" Title: %s (%s)", info->name, info->description);
dvander@605: } else {
dvander@605: g_RootMenu.ConsolePrint(" Title: %s", info->name);
dvander@605: }
dvander@605: }
dvander@605: if (IS_STR_FILLED(info->author))
dvander@605: {
dvander@605: g_RootMenu.ConsolePrint(" Author: %s", info->author);
dvander@315: }
dvander@315: if (IS_STR_FILLED(info->version))
dvander@315: {
dvander@315: g_RootMenu.ConsolePrint(" Version: %s", info->version);
dvander@315: }
dvander@315: if (IS_STR_FILLED(info->url))
dvander@315: {
dvander@315: g_RootMenu.ConsolePrint(" URL: %s", info->url);
dvander@315: }
dvander@605: if (pl->GetStatus() == Plugin_Error)
dvander@315: {
dvander@605: g_RootMenu.ConsolePrint(" Error: %s", pl->m_errormsg);
dvander@605: } else {
ds@860: g_RootMenu.ConsolePrint(" Debugging: %s", pl->IsDebugging() ? "Yes" : "No");
ds@860: g_RootMenu.ConsolePrint(" Running: %s", pl->GetStatus() == Plugin_Running ? "Yes" : "No");
ds@860:
ds@861: const char *typestr = "";
ds@860: switch (pl->GetType())
ds@860: {
ds@860: case PluginType_MapUpdated:
ds@860: typestr = "Map Change if Updated";
ds@860: break;
ds@860: case PluginType_MapOnly:
ds@860: typestr = "Map Change";
ds@860: break;
ds@860: case PluginType_Private:
ds@860: case PluginType_Global:
ds@860: typestr = "Never";
ds@860: break;
ds@860: }
ds@860:
ds@860: g_RootMenu.ConsolePrint(" Reloads: %s", typestr);
dvander@315: }
dvander@315: } else {
dvander@315: g_RootMenu.ConsolePrint(" Load error: %s", pl->m_errormsg);
dvander@315: g_RootMenu.ConsolePrint(" File info: (title \"%s\") (version \"%s\")",
dvander@315: info->name ? info->name : "",
dvander@315: info->version ? info->version : "");
dvander@315: if (IS_STR_FILLED(info->url))
dvander@315: {
dvander@315: g_RootMenu.ConsolePrint(" File URL: %s", info->url);
dvander@315: }
dvander@309: }
dvander@309:
dvander@309: return;
dvander@309: } else if (strcmp(cmd, "debug") == 0) {
dvander@309: if (argcount < 5)
dvander@309: {
dvander@310: g_RootMenu.ConsolePrint("[SM] Usage: sm plugins debug <#> [on|off]");
dvander@309: return;
dvander@309: }
dvander@309:
faluco@1541: int num = atoi(command.Arg(3));
dvander@309: if (num < 1 || num > (int)GetPluginCount())
dvander@309: {
dvander@310: g_RootMenu.ConsolePrint("[SM] Plugin index not found.");
dvander@309: return;
dvander@309: }
dvander@309:
dvander@309: int res;
faluco@1541: const char *mode = command.Arg(4);
dvander@309: if ((res=strcmp("on", mode)) && strcmp("off", mode))
dvander@309: {
dvander@310: g_RootMenu.ConsolePrint("[SM] The only possible options are \"on\" and \"off.\"");
dvander@309: return;
dvander@309: }
dvander@309:
dvander@309: bool debug;
dvander@309: if (!res)
dvander@309: {
dvander@309: debug = true;
dvander@309: } else {
dvander@309: debug = false;
dvander@309: }
dvander@309:
dvander@309: CPlugin *pl = GetPluginByOrder(num);
dvander@309: if (debug && pl->IsDebugging())
dvander@309: {
dvander@309: g_RootMenu.ConsolePrint("[SM] This plugin is already in debug mode.");
dvander@309: return;
dvander@309: } else if (!debug && !pl->IsDebugging()) {
dvander@309: g_RootMenu.ConsolePrint("[SM] Debug mode is already disabled in this plugin.");
dvander@309: return;
dvander@309: }
dvander@309:
dvander@309: char error[256];
dvander@309: if (pl->ToggleDebugMode(debug, error, sizeof(error)))
dvander@309: {
dvander@310: g_RootMenu.ConsolePrint("[SM] Successfully toggled debug mode on plugin %s.", pl->GetFilename());
dvander@309: return;
dvander@309: } else {
dvander@309: g_RootMenu.ConsolePrint("[SM] Could not toggle debug mode on plugin %s.", pl->GetFilename());
dvander@309: g_RootMenu.ConsolePrint("[SM] Plugin returned error: %s", error);
dvander@309: return;
dvander@309: }
faluco@1348: } else if (strcmp(cmd, "reload") == 0) {
faluco@1348: if (argcount < 4)
faluco@1348: {
faluco@1348: g_RootMenu.ConsolePrint("[SM] Usage: sm plugins reload <#|file>");
faluco@1348: return;
faluco@1348: }
faluco@1348:
faluco@1348: CPlugin *pl;
faluco@1348: char *end;
faluco@1541: const char *arg = command.Arg(3);
faluco@1348: int id = strtol(arg, &end, 10);
faluco@1348:
faluco@1348: if (*end == '\0')
faluco@1348: {
faluco@1348: pl = GetPluginByOrder(id);
faluco@1348: if (!pl)
faluco@1348: {
faluco@1348: g_RootMenu.ConsolePrint("[SM] Plugin index %d not found.", id);
faluco@1348: return;
faluco@1348: }
faluco@1348: } else {
faluco@1348: char pluginfile[256];
faluco@1348: const char *ext = g_LibSys.GetFileExtension(arg) ? "" : ".smx";
faluco@1348: UTIL_Format(pluginfile, sizeof(pluginfile), "%s%s", arg, ext);
faluco@1348:
faluco@1348: if (!sm_trie_retrieve(m_LoadLookup, pluginfile, (void **)&pl))
faluco@1348: {
faluco@1348: g_RootMenu.ConsolePrint("[SM] Plugin %s is not loaded.", pluginfile);
faluco@1348: return;
faluco@1348: }
faluco@1348: }
faluco@1348:
faluco@1348: char name[PLATFORM_MAX_PATH];
faluco@1348: const sm_plugininfo_t *info = pl->GetPublicInfo();
faluco@1348: strcpy(name, (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename());
faluco@1348:
faluco@1348: if (ReloadPlugin(pl))
faluco@1348: {
faluco@1348: g_RootMenu.ConsolePrint("[SM] Plugin %s reloaded successfully.", name);
faluco@1348: } else {
faluco@1348: g_RootMenu.ConsolePrint("[SM] Failed to reload plugin %s.", name);
faluco@1348: }
faluco@1348:
faluco@1348: return;
dvander@309: }
dvander@309: }
dvander@309:
dvander@309: /* Draw the main menu */
dvander@309: g_RootMenu.ConsolePrint("SourceMod Plugins Menu:");
dvander@309: g_RootMenu.DrawGenericOption("list", "Show loaded plugins");
dvander@309: g_RootMenu.DrawGenericOption("load", "Load a plugin");
dvander@309: g_RootMenu.DrawGenericOption("unload", "Unload a plugin");
dvander@309: g_RootMenu.DrawGenericOption("info", "Information about a plugin");
dvander@309: g_RootMenu.DrawGenericOption("debug", "Toggle debug mode on a plugin");
faluco@1348: g_RootMenu.DrawGenericOption("reload", "Reloads a plugin");
faluco@1348: }
faluco@1348:
faluco@1348: bool CPluginManager::ReloadPlugin(CPlugin *pl)
faluco@1348: {
faluco@1348: List::iterator iter;
faluco@1348: char filename[PLATFORM_MAX_PATH];
faluco@1348: bool debug, wasloaded;
faluco@1348: PluginType ptype;
faluco@1348: IPlugin *newpl;
faluco@1348: int id = 1;
faluco@1348:
faluco@1348: strcpy(filename, pl->m_filename);
faluco@1348: debug = pl->IsDebugging();
faluco@1348: ptype = pl->GetType();
faluco@1348:
faluco@1348: for (iter=m_plugins.begin(); iter!=m_plugins.end(); iter++, id++)
faluco@1348: {
faluco@1348: if ((*iter) == pl)
faluco@1348: {
faluco@1348: break;
faluco@1348: }
faluco@1348: }
faluco@1348:
faluco@1348: if (!UnloadPlugin(pl))
faluco@1348: {
faluco@1348: return false;
faluco@1348: }
faluco@1348: if (!(newpl=LoadPlugin(filename, debug, ptype, NULL, 0, &wasloaded)))
faluco@1348: {
faluco@1348: return false;
faluco@1348: }
faluco@1348:
faluco@1348: for (iter=m_plugins.begin(); iter!=m_plugins.end(); iter++)
faluco@1348: {
faluco@1348: if ((*iter) == (CPlugin *)newpl)
faluco@1348: {
faluco@1348: m_plugins.erase(iter);
faluco@1348: break;
faluco@1348: }
faluco@1348: }
faluco@1348:
faluco@1348: int i;
faluco@1348: for (i=1, iter=m_plugins.begin(); iter!=m_plugins.end() && i::iterator iter;
faluco@333: List tmp_list = m_plugins;
faluco@333: CPlugin *pl;
faluco@333: time_t t;
faluco@333:
faluco@333: for (iter=tmp_list.begin(); iter!=tmp_list.end(); iter++)
faluco@333: {
faluco@333: pl = (*iter);
faluco@333: if (pl->GetType() == PluginType_MapOnly)
faluco@333: {
faluco@333: UnloadPlugin((IPlugin *)pl);
faluco@333: } else if (pl->GetType() == PluginType_MapUpdated) {
dvander@450: t = pl->GetFileTimeStamp();
dvander@450: if (!t || t > pl->GetTimeStamp())
faluco@333: {
faluco@333: pl->SetTimeStamp(t);
faluco@333: UnloadPlugin((IPlugin *)pl);
faluco@333: }
faluco@333: }
faluco@333: }
faluco@333: }
faluco@430:
faluco@430: void CPluginManager::_SetPauseState(CPlugin *pl, bool paused)
faluco@430: {
faluco@430: List::iterator iter;
faluco@430: IPluginsListener *pListener;
faluco@430: for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++)
faluco@430: {
faluco@430: pListener = (*iter);
faluco@430: pListener->OnPluginPauseChange(pl, paused);
faluco@430: }
dvander@464: }
dvander@464:
dvander@601: bool CPluginManager::AddFakeNative(IPluginFunction *pFunction, const char *name, SPVM_FAKENATIVE_FUNC func)
dvander@601: {
dvander@601: if (sm_trie_retrieve(m_pNativeLookup, name, NULL))
dvander@601: {
dvander@601: return false;
dvander@601: }
dvander@601:
dvander@601: FakeNative *pNative = new FakeNative;
dvander@601:
dvander@601: pNative->func = g_pVM->CreateFakeNative(func, pNative);
dvander@601: if (!pNative->func)
dvander@601: {
dvander@601: delete pNative;
dvander@601: return false;
dvander@601: }
dvander@601:
dvander@601: pNative->call = pFunction;
dvander@601: pNative->name.assign(name);
dvander@601: pNative->ctx = pFunction->GetParentContext();
dvander@601:
dvander@601: m_Natives.push_back(pNative);
dvander@601: sm_trie_insert(m_pNativeLookup, name,pNative);
dvander@601:
dvander@605: CPlugin *pPlugin = GetPluginByCtx(pNative->ctx->GetContext());
dvander@605: pPlugin->m_fakeNatives.push_back(pNative);
dvander@605:
dvander@601: return true;
dvander@601: }
ds@611:
ds@611: void CPluginManager::AddFunctionsToForward(const char *name, IChangeableForward *pForward)
ds@611: {
ds@611: List::iterator iter;
ds@611: CPlugin *pPlugin;
ds@611: IPluginFunction *pFunction;
ds@611:
ds@611: for (iter = m_plugins.begin(); iter != m_plugins.end(); iter++)
ds@611: {
ds@611: pPlugin = (*iter);
ds@611:
ds@611: if (pPlugin->GetStatus() <= Plugin_Paused)
ds@611: {
ds@611: pFunction = pPlugin->GetBaseContext()->GetFunctionByName(name);
ds@611:
ds@611: if (pFunction)
ds@611: {
ds@611: pForward->AddFunction(pFunction);
ds@611: }
ds@611: }
ds@611: }
ds@611: }
dvander@900:
dvander@900: CPlugin *CPluginManager::GetPluginFromIdentity(IdentityToken_t *pToken)
dvander@900: {
dvander@900: if (pToken->type != g_PluginIdent)
dvander@900: {
dvander@900: return NULL;
dvander@900: }
dvander@900:
dvander@900: return (CPlugin *)(pToken->ptr);
dvander@900: }
dvander@978:
dvander@1124: void CPluginManager::OnLibraryAction(const char *lib, bool drop)
dvander@978: {
dvander@978: List::iterator iter;
dvander@978:
dvander@1124: struct _pl
dvander@1124: {
dvander@1124: cell_t name;
dvander@1124: cell_t file;
dvander@1124: cell_t required;
dvander@1124: } *plc;
dvander@1124:
dvander@1124: const char *name = drop ? "OnLibraryRemoved" : "OnLibraryAdded";
dvander@1124:
dvander@1124: for (iter=m_plugins.begin();
dvander@1124: iter!=m_plugins.end();
dvander@1124: iter++)
dvander@1124: {
dvander@1124: CPlugin *pl = (*iter);
dvander@1124: if (pl->GetStatus() != Plugin_Running)
dvander@1124: {
dvander@1124: continue;
dvander@1124: }
dvander@1124: IPluginContext *pContext = pl->GetBaseContext();
dvander@1124: IPluginFunction *pf = pContext->GetFunctionByName(name);
dvander@1124: if (!pf)
dvander@1124: {
dvander@1124: continue;
dvander@1124: }
dvander@1124: uint32_t num_vars = pContext->GetPubVarsNum();
dvander@1124: for (uint32_t i=0; iGetPubvarByIndex(i, &pubvar) != SP_ERROR_NONE)
dvander@1124: {
dvander@1124: continue;
dvander@1124: }
dvander@1124: if (strncmp(pubvar->name, "__pl_", 5) != 0)
dvander@1124: {
dvander@1124: continue;
dvander@1124: }
dvander@1124: plc = (_pl *)pubvar->offs;
dvander@1124: if (plc->required)
dvander@1124: {
dvander@1124: continue;
dvander@1124: }
dvander@1124: char *str;
dvander@1124: pContext->LocalToString(plc->name, &str);
dvander@1124: if (strcmp(str, lib) != 0)
dvander@1124: {
dvander@1124: continue;
dvander@1124: }
dvander@1124: pf->PushString(lib);
dvander@1124: pf->Execute(NULL);
dvander@1124: }
dvander@1124: }
dvander@978: }
dvander@1124:
dvander@1124: bool CPluginManager::LibraryExists(const char *lib)
dvander@1124: {
dvander@1124: List::iterator iter;
dvander@1124:
dvander@1124: for (iter=m_plugins.begin();
dvander@1124: iter!=m_plugins.end();
dvander@1124: iter++)
dvander@1124: {
dvander@1124: CPlugin *pl = (*iter);
dvander@1124: if (pl->GetStatus() != Plugin_Running)
dvander@1124: {
dvander@1124: continue;
dvander@1124: }
dvander@1124: List::iterator s_iter;
dvander@1124: for (s_iter = pl->m_Libraries.begin();
dvander@1124: s_iter != pl->m_Libraries.end();
dvander@1124: s_iter++)
dvander@1124: {
dvander@1124: if ((*s_iter).compare(lib) == 0)
dvander@1124: {
dvander@1124: return true;
dvander@1124: }
dvander@1124: }
dvander@1124: }
dvander@1124:
dvander@1124: return false;
dvander@1124: }
faluco@1221:
faluco@1221: void CPluginManager::AllPluginsLoaded()
faluco@1221: {
faluco@1221: List::iterator iter;
faluco@1221: CPlugin *pl;
faluco@1221:
faluco@1221: for (iter=m_plugins.begin(); iter!=m_plugins.end(); iter++)
faluco@1221: {
faluco@1221: pl = (*iter);
faluco@1221: pl->Call_OnAllPluginsLoaded();
faluco@1221: }
dvander@1232: }