1.1 --- a/core/systems/PluginSys.cpp Wed Dec 13 11:14:25 2006 +0000
1.2 +++ b/core/systems/PluginSys.cpp Wed Dec 13 11:16:20 2006 +0000
1.3 @@ -2,6 +2,7 @@
1.4 #include "PluginSys.h"
1.5 #include "LibrarySys.h"
1.6 #include "sourcemm_api.h"
1.7 +#include "sourcemod.h"
1.8 #include "CTextParsers.h"
1.9
1.10 CPluginManager g_PluginMngr;
1.11 @@ -10,86 +11,204 @@
1.12 {
1.13 }
1.14
1.15 -CPlugin *CPlugin::CreatePlugin(const char *file,
1.16 - bool debug_default,
1.17 - PluginType type,
1.18 - char *error,
1.19 - size_t maxlen)
1.20 +CPlugin::CPlugin(const char *file)
1.21 +{
1.22 + static int MySerial = 0;
1.23 +
1.24 + m_type = PluginType_Private;
1.25 + m_status = Plugin_Uncompiled;
1.26 + m_serial = ++MySerial;
1.27 + m_plugin = NULL;
1.28 + m_funcsnum = 0;
1.29 + m_priv_funcs = NULL;
1.30 + m_pub_funcs = NULL;
1.31 + m_errormsg[256] = '\0';
1.32 + snprintf(m_filename, sizeof(m_filename), "%s", file);
1.33 +}
1.34 +
1.35 +CPlugin::~CPlugin()
1.36 {
1.37 - static unsigned int MySerial = 0;
1.38 - FILE *fp = fopen(file, "rb");
1.39 + if (m_ctx.base)
1.40 + {
1.41 + g_pSourcePawn->FreeBaseContext(m_ctx.base);
1.42 + m_ctx.base = NULL;
1.43 + }
1.44 + if (m_ctx.ctx)
1.45 + {
1.46 + m_ctx.vm->FreeContext(m_ctx.ctx);
1.47 + m_ctx.ctx = NULL;
1.48 + }
1.49 + if (m_ctx.co)
1.50 + {
1.51 + m_ctx.vm->AbortCompilation(m_ctx.co);
1.52 + m_ctx.co = NULL;
1.53 + }
1.54 +
1.55 + if (m_plugin)
1.56 + {
1.57 + g_pSourcePawn->FreeFromMemory(m_plugin);
1.58 + m_plugin = NULL;
1.59 + }
1.60 +
1.61 + if (m_pub_funcs)
1.62 + {
1.63 + for (uint32_t i=0; i<m_plugin->info.publics_num; i++)
1.64 + {
1.65 + g_PluginMngr.ReleaseFunctionToPool(m_pub_funcs[i]);
1.66 + }
1.67 + delete [] m_pub_funcs;
1.68 + m_pub_funcs = NULL;
1.69 + }
1.70 +
1.71 + if (m_priv_funcs)
1.72 + {
1.73 + for (unsigned int i=0; i<m_funcsnum; i++)
1.74 + {
1.75 + g_PluginMngr.ReleaseFunctionToPool(m_priv_funcs[i]);
1.76 + }
1.77 + delete [] m_priv_funcs;
1.78 + m_priv_funcs = NULL;
1.79 + }
1.80 +}
1.81 +
1.82 +CPlugin *CPlugin::CreatePlugin(const char *file, char *error, size_t maxlength)
1.83 +{
1.84 + char fullpath[PLATFORM_MAX_PATH+1];
1.85 + g_LibSys.PathFormat(fullpath, sizeof(fullpath), "%s/plugins/%s", g_SourceMod.GetSMBaseDir(), file);
1.86 + FILE *fp = fopen(fullpath, "rb");
1.87
1.88 if (!fp)
1.89 {
1.90 - snprintf(error, maxlen, "Could not open file");
1.91 - return NULL;
1.92 + if (error)
1.93 + {
1.94 + snprintf(error, maxlength, "Unable to open file");
1.95 + return NULL;
1.96 + } else {
1.97 + CPlugin *pPlugin = new CPlugin(file);
1.98 + snprintf(pPlugin->m_errormsg, sizeof(pPlugin->m_errormsg), "Unable to open file");
1.99 + pPlugin->m_status = Plugin_BadLoad;
1.100 + return pPlugin;
1.101 + }
1.102 }
1.103
1.104 int err;
1.105 sp_plugin_t *pl = g_pSourcePawn->LoadFromFilePointer(fp, &err);
1.106 if (pl == NULL)
1.107 {
1.108 - snprintf(error, maxlen, "Could not load plugin, error %d", err);
1.109 - return NULL;
1.110 + fclose(fp);
1.111 + if (error)
1.112 + {
1.113 + snprintf(error, maxlength, "Error %d while parsing plugin", err);
1.114 + return NULL;
1.115 + } else {
1.116 + CPlugin *pPlugin = new CPlugin(file);
1.117 + snprintf(pPlugin->m_errormsg, sizeof(pPlugin->m_errormsg), "Error %d while parsing plugin", err);
1.118 + pPlugin->m_status = Plugin_BadLoad;
1.119 + return pPlugin;
1.120 + }
1.121 }
1.122
1.123 fclose(fp);
1.124
1.125 - ICompilation *co = g_pVM->StartCompilation(pl);
1.126 -
1.127 - if (debug_default)
1.128 + CPlugin *pPlugin = new CPlugin(file);
1.129 + pPlugin->m_plugin = pl;
1.130 + return pPlugin;
1.131 +}
1.132 +
1.133 +ICompilation *CPlugin::StartMyCompile(IVirtualMachine *vm)
1.134 +{
1.135 + if (!m_plugin)
1.136 {
1.137 - if (!g_pVM->SetCompilationOption(co, "debug", "1"))
1.138 - {
1.139 - g_pVM->AbortCompilation(co);
1.140 - snprintf(error, maxlen, "Could not set plugin to debug mode");
1.141 - return NULL;
1.142 - }
1.143 + return NULL;
1.144 }
1.145
1.146 - sp_context_t *ctx = g_pVM->CompileToContext(co, &err);
1.147 - if (ctx == NULL)
1.148 + /* :NOTICE: We will eventually need to change these natives
1.149 + * for swapping in new contexts
1.150 + */
1.151 + if (m_ctx.co || m_ctx.ctx)
1.152 {
1.153 - snprintf(error, maxlen, "Plugin failed to load, JIT error: %d", err);
1.154 return NULL;
1.155 }
1.156
1.157 - IPluginContext *base = g_pSourcePawn->CreateBaseContext(ctx);
1.158 - CPlugin *pPlugin = new CPlugin;
1.159 + m_status = Plugin_Uncompiled;
1.160
1.161 - snprintf(pPlugin->m_filename, PLATFORM_MAX_PATH, "%s", file);
1.162 - pPlugin->m_debugging = debug_default;
1.163 - pPlugin->m_ctx_current.base = base;
1.164 - pPlugin->m_ctx_current.ctx = ctx;
1.165 - pPlugin->m_type = type;
1.166 - pPlugin->m_serial = ++MySerial;
1.167 - pPlugin->m_status = Plugin_Loaded;
1.168 - pPlugin->m_plugin = pl;
1.169 + m_ctx.vm = vm;
1.170 + m_ctx.co = vm->StartCompilation(m_plugin);
1.171 +
1.172 + return m_ctx.co;
1.173 +}
1.174
1.175 - pPlugin->UpdateInfo();
1.176 -
1.177 - ctx->user[SM_CONTEXTVAR_MYSELF] = (void *)(IPlugin *)pPlugin;
1.178 -
1.179 - /* Build function information loosely */
1.180 - pPlugin->m_funcsnum = g_pVM->FunctionCount(ctx);
1.181 +void CPlugin::CancelMyCompile()
1.182 +{
1.183 + if (!m_ctx.co)
1.184 + {
1.185 + return;
1.186 + }
1.187
1.188 - if (pPlugin->m_funcsnum)
1.189 + m_ctx.vm->AbortCompilation(m_ctx.co);
1.190 + m_ctx.co = NULL;
1.191 + m_ctx.vm = NULL;
1.192 +}
1.193 +
1.194 +bool CPlugin::FinishMyCompile(char *error, size_t maxlength)
1.195 +{
1.196 + if (!m_ctx.co)
1.197 {
1.198 - pPlugin->m_priv_funcs = new CFunction *[pPlugin->m_funcsnum];
1.199 - memset(pPlugin->m_priv_funcs, 0, sizeof(CFunction *) * pPlugin->m_funcsnum);
1.200 - } else {
1.201 - pPlugin->m_priv_funcs = NULL;
1.202 + return false;
1.203 }
1.204
1.205 - if (pl->info.publics_num)
1.206 + int err;
1.207 + m_ctx.ctx = m_ctx.vm->CompileToContext(m_ctx.co, &err);
1.208 + if (!m_ctx.ctx)
1.209 {
1.210 - pPlugin->m_pub_funcs = new CFunction *[pl->info.publics_num];
1.211 - memset(pPlugin->m_pub_funcs, 0, sizeof(CFunction *) * pl->info.publics_num);
1.212 - } else {
1.213 - pPlugin->m_pub_funcs = NULL;
1.214 + memset(&m_ctx, 0, sizeof(m_ctx));
1.215 + if (!error)
1.216 + {
1.217 + SetErrorState(Plugin_Error, "Failed to compile (error %d)", err);
1.218 + } else {
1.219 + snprintf(error, maxlength, "Failed to compile (error %d)", err);
1.220 + }
1.221 + return false;
1.222 }
1.223
1.224 - return pPlugin;
1.225 + m_ctx.base = g_pSourcePawn->CreateBaseContext(m_ctx.ctx);
1.226 + m_ctx.ctx->user[SM_CONTEXTVAR_MYSELF] = (void *)this;
1.227 +
1.228 + m_funcsnum = m_ctx.vm->FunctionCount(m_ctx.ctx);
1.229 +
1.230 + /**
1.231 + * Note: Since the m_plugin member will never change,
1.232 + * it is safe to assume the function count will never change
1.233 + */
1.234 + if (m_funcsnum && m_priv_funcs == NULL)
1.235 + {
1.236 + m_priv_funcs = new CFunction *[m_funcsnum];
1.237 + memset(m_priv_funcs, 0, sizeof(CFunction *) * m_funcsnum);
1.238 + } else {
1.239 + m_priv_funcs = NULL;
1.240 + }
1.241 +
1.242 + if (m_plugin->info.publics_num && m_pub_funcs == NULL)
1.243 + {
1.244 + m_pub_funcs = new CFunction *[m_plugin->info.publics_num];
1.245 + memset(m_pub_funcs, 0, sizeof(CFunction *) * m_plugin->info.publics_num);
1.246 + } else {
1.247 + m_pub_funcs = NULL;
1.248 + }
1.249 +
1.250 + UpdateInfo();
1.251 +
1.252 + return true;
1.253 +}
1.254 +
1.255 +void CPlugin::SetErrorState(PluginStatus status, const char *error_fmt, ...)
1.256 +{
1.257 + m_status = status;
1.258 +
1.259 + va_list ap;
1.260 + va_start(ap, error_fmt);
1.261 + vsnprintf(m_errormsg, sizeof(m_errormsg), error_fmt, ap);
1.262 + va_end(ap);
1.263 }
1.264
1.265 IPluginFunction *CPlugin::GetFunctionById(funcid_t func_id)
1.266 @@ -113,7 +232,7 @@
1.267 } else {
1.268 func_id >>= 1;
1.269 unsigned int index;
1.270 - if (!g_pVM->FunctionLookup(m_ctx_current.ctx, func_id, &index))
1.271 + if (!g_pVM->FunctionLookup(m_ctx.ctx, func_id, &index))
1.272 {
1.273 return NULL;
1.274 }
1.275 @@ -131,7 +250,7 @@
1.276 IPluginFunction *CPlugin::GetFunctionByName(const char *public_name)
1.277 {
1.278 uint32_t index;
1.279 - IPluginContext *base = m_ctx_current.base;
1.280 + IPluginContext *base = m_ctx.base;
1.281
1.282 if (base->FindPublicByName(public_name, &index) != SP_ERROR_NONE)
1.283 {
1.284 @@ -195,12 +314,12 @@
1.285
1.286 IPluginContext *CPlugin::GetBaseContext() const
1.287 {
1.288 - return m_ctx_current.base;
1.289 + return m_ctx.base;
1.290 }
1.291
1.292 sp_context_t *CPlugin::GetContext() const
1.293 {
1.294 - return m_ctx_current.ctx;
1.295 + return m_ctx.ctx;
1.296 }
1.297
1.298 const char *CPlugin::GetFilename() const
1.299 @@ -230,7 +349,12 @@
1.300
1.301 bool CPlugin::IsDebugging() const
1.302 {
1.303 - return m_debugging;
1.304 + if (!m_ctx.ctx)
1.305 + {
1.306 + return false;
1.307 + }
1.308 +
1.309 + return ((m_ctx.ctx->flags & SP_FLAG_DEBUG) == SP_FLAG_DEBUG);
1.310 }
1.311
1.312 bool CPlugin::SetPauseState(bool paused)
1.313 @@ -299,30 +423,158 @@
1.314 /* :TODO: log the error, don't bail out though */
1.315 }
1.316
1.317 + LoadPluginsFromDir(basedir, NULL);
1.318 +}
1.319
1.320 - //:TODO: move this to a separate recursive function and do stuff
1.321 - /*IDirectory *dir = g_LibSys.OpenDirectory(basedir);
1.322 +void CPluginManager::LoadPluginsFromDir(const char *basedir, const char *localpath)
1.323 +{
1.324 + char base_path[PLATFORM_MAX_PATH+1];
1.325 +
1.326 + /* Form the current path to start reading from */
1.327 + if (localpath == NULL)
1.328 + {
1.329 + g_LibSys.PathFormat(base_path, sizeof(base_path), "%s", basedir);
1.330 + } else {
1.331 + g_LibSys.PathFormat(base_path, sizeof(base_path), "%s/%s", basedir, localpath);
1.332 + }
1.333 +
1.334 + IDirectory *dir = g_LibSys.OpenDirectory(base_path);
1.335 +
1.336 + if (!dir)
1.337 + {
1.338 + //:TODO: write a logger and LOG THIS UP, BABY
1.339 + //g_LibSys.GetPlatformError(error, err_max);
1.340 + return;
1.341 + }
1.342 +
1.343 while (dir->MoreFiles())
1.344 {
1.345 - if (dir->IsEntryDirectory() && (strcmp(dir->GetEntryName(), "disabled") != 0))
1.346 + if (dir->IsEntryDirectory()
1.347 + && (strcmp(dir->GetEntryName(), ".") != 0)
1.348 + && (strcmp(dir->GetEntryName(), "..") != 0)
1.349 + && (strcmp(dir->GetEntryName(), "disabled") != 0)
1.350 + && (strcmp(dir->GetEntryName(), "optional") != 0))
1.351 {
1.352 - char path[PLATFORM_MAX_PATH+1];
1.353 - g_SMAPI->PathFormat(path, sizeof(path)-1, "%s/%s", basedir, dir->GetEntryName());
1.354 - RefreshOrLoadPlugins(basedir);
1.355 + char new_local[PLATFORM_MAX_PATH+1];
1.356 + if (localpath == NULL)
1.357 + {
1.358 + /* If no path yet, don't add a former slash */
1.359 + snprintf(new_local, sizeof(new_local), "%s", dir->GetEntryName());
1.360 + } else {
1.361 + g_LibSys.PathFormat(new_local, sizeof(new_local), "%s/%s", localpath, dir->GetEntryName());
1.362 + }
1.363 + LoadPluginsFromDir(basedir, new_local);
1.364 + } else if (dir->IsEntryFile()) {
1.365 + const char *name = dir->GetEntryName();
1.366 + size_t len = strlen(name);
1.367 + if (len < 4
1.368 + || strcmp(&name[len-4], ".smx") != 0)
1.369 + {
1.370 + continue;
1.371 + }
1.372 + /* If the filename matches, load the plugin */
1.373 + char plugin[PLATFORM_MAX_PATH+1];
1.374 + if (localpath == NULL)
1.375 + {
1.376 + snprintf(plugin, sizeof(plugin), "%s", name);
1.377 + } else {
1.378 + g_LibSys.PathFormat(plugin, sizeof(plugin), "%s/%s", localpath, name);
1.379 + }
1.380 + LoadAutoPlugin(plugin);
1.381 + }
1.382 + dir->NextEntry();
1.383 + }
1.384 + g_LibSys.CloseDirectory(dir);
1.385 +}
1.386 +
1.387 +void CPluginManager::LoadAutoPlugin(const char *file)
1.388 +{
1.389 + CPlugin *pPlugin = CPlugin::CreatePlugin(file, NULL, 0);
1.390 +
1.391 + assert(pPlugin != NULL);
1.392 +
1.393 + pPlugin->m_type = PluginType_MapUpdated;
1.394 +
1.395 + ICompilation *co = NULL;
1.396 +
1.397 + if (pPlugin->m_status == Plugin_Uncompiled)
1.398 + {
1.399 + co = pPlugin->StartMyCompile(g_pVM);
1.400 + }
1.401 +
1.402 + PluginSettings *pset;
1.403 + unsigned int setcount = m_PluginInfo.GetSettingsNum();
1.404 + for (unsigned int i=0; i<setcount; i++)
1.405 + {
1.406 + pset = m_PluginInfo.GetSettingsIfMatch(i, file);
1.407 + if (!pset)
1.408 + {
1.409 + continue;
1.410 + }
1.411 + pPlugin->m_type = pset->type_val;
1.412 + if (co)
1.413 + {
1.414 + for (unsigned int j=0; j<pset->opts_num; j++)
1.415 + {
1.416 + const char *key, *val;
1.417 + m_PluginInfo.GetOptionsForPlugin(pset, j, &key, &val);
1.418 + if (!key || !val)
1.419 + {
1.420 + continue;
1.421 + }
1.422 + if (!g_pVM->SetCompilationOption(co, key, val))
1.423 + {
1.424 + pPlugin->SetErrorState(Plugin_Error, "Unable to set option (key \"%s\") (value \"%s\")", key, val);
1.425 + pPlugin->CancelMyCompile();
1.426 + co = NULL;
1.427 + break;
1.428 + }
1.429 + }
1.430 }
1.431 }
1.432 - g_LibSys.CloseDirectory(dir);*/
1.433 +
1.434 + if (co)
1.435 + {
1.436 + pPlugin->FinishMyCompile(NULL, 0);
1.437 + co = NULL;
1.438 + }
1.439 +
1.440 + InitAndAddPlugin(pPlugin);
1.441 }
1.442
1.443 IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType type, char error[], size_t err_max)
1.444 {
1.445 - CPlugin *pPlugin = CPlugin::CreatePlugin(path, debug, type, error, err_max);
1.446 + CPlugin *pPlugin = CPlugin::CreatePlugin(path, error, err_max);
1.447
1.448 if (!pPlugin)
1.449 {
1.450 return NULL;
1.451 }
1.452
1.453 + ICompilation *co = pPlugin->StartMyCompile(g_pVM);
1.454 + if (!co || (debug && !g_pVM->SetCompilationOption(co, "debug", "1")))
1.455 + {
1.456 + snprintf(error, err_max, "Unable to start%s compilation", debug ? " debug" : "");
1.457 + pPlugin->CancelMyCompile();
1.458 + delete pPlugin;
1.459 + return NULL;
1.460 + }
1.461 +
1.462 + if (!pPlugin->FinishMyCompile(error, err_max))
1.463 + {
1.464 + delete pPlugin;
1.465 + return NULL;
1.466 + }
1.467 +
1.468 + pPlugin->m_type = type;
1.469 +
1.470 + InitAndAddPlugin(pPlugin);
1.471 +
1.472 + return pPlugin;
1.473 +}
1.474 +
1.475 +void CPluginManager::InitAndAddPlugin(CPlugin *pPlugin)
1.476 +{
1.477 m_plugins.push_back(pPlugin);
1.478
1.479 List<IPluginsListener *>::iterator iter;
1.480 @@ -334,8 +586,6 @@
1.481 }
1.482
1.483 /* :TODO: a lot more... */
1.484 -
1.485 - return pPlugin;
1.486 }
1.487
1.488 bool CPluginManager::UnloadPlugin(IPlugin *plugin)
1.489 @@ -352,45 +602,6 @@
1.490 pListener->OnPluginDestroyed(pPlugin);
1.491 }
1.492
1.493 - if (pPlugin->m_pub_funcs)
1.494 - {
1.495 - for (uint32_t i=0; i<pPlugin->m_plugin->info.publics_num; i++)
1.496 - {
1.497 - g_PluginMngr.ReleaseFunctionToPool(pPlugin->m_pub_funcs[i]);
1.498 - }
1.499 - delete [] pPlugin->m_pub_funcs;
1.500 - pPlugin->m_pub_funcs = NULL;
1.501 - }
1.502 -
1.503 - if (pPlugin->m_priv_funcs)
1.504 - {
1.505 - for (unsigned int i=0; i<pPlugin->m_funcsnum; i++)
1.506 - {
1.507 - g_PluginMngr.ReleaseFunctionToPool(pPlugin->m_priv_funcs[i]);
1.508 - }
1.509 - delete [] pPlugin->m_priv_funcs;
1.510 - pPlugin->m_priv_funcs = NULL;
1.511 - }
1.512 -
1.513 - if (pPlugin->m_ctx_current.base)
1.514 - {
1.515 - g_pSourcePawn->FreeBaseContext(pPlugin->m_ctx_current.base);
1.516 - }
1.517 - if (pPlugin->m_ctx_backup.base)
1.518 - {
1.519 - g_pSourcePawn->FreeBaseContext(pPlugin->m_ctx_backup.base);
1.520 - }
1.521 - if (pPlugin->m_ctx_current.ctx)
1.522 - {
1.523 - pPlugin->m_ctx_current.ctx->vmbase->FreeContext(pPlugin->m_ctx_current.ctx);
1.524 - }
1.525 - if (pPlugin->m_ctx_backup.ctx)
1.526 - {
1.527 - pPlugin->m_ctx_backup.ctx->vmbase->FreeContext(pPlugin->m_ctx_backup.ctx);
1.528 - }
1.529 -
1.530 - g_pSourcePawn->FreeFromMemory(pPlugin->m_plugin);
1.531 -
1.532 delete pPlugin;
1.533
1.534 return true;
1.535 @@ -477,7 +688,7 @@
1.536 ptr++;
1.537 }
1.538
1.539 - if (alias_path_end == alias_len - 1)
1.540 + if (alias_explicit_paths && alias_path_end == alias_len - 1)
1.541 {
1.542 /* Trailing slash is totally invalid here */
1.543 return false;