initial import of plugin database (UNTESTED)

added file pattern matching routine (TESTED)
added memtable caching (UNTESTED)

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40208
This commit is contained in:
David Anderson 2006-12-10 09:19:59 +00:00
parent f807575429
commit a1e58aa9ef
9 changed files with 764 additions and 7 deletions

View File

@ -587,6 +587,8 @@ failed:
*line = curline; *line = curline;
} }
smc->ReadSMC_ParseEnd(true, (err == SMCParse_Custom));
if (col) if (col)
{ {
*col = curtok; *col = curtok;

View File

@ -41,7 +41,7 @@
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
Optimization="0" Optimization="0"
AdditionalIncludeDirectories="..\interfaces;..\;..\systems;..\..\sourcepawn\include" AdditionalIncludeDirectories="..\interfaces;..\;..\systems;..\..\sourcepawn\include"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SOURCEMOD_MM_EXPORTS;_CRT_SECURE_NO_DEPRECATE" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SOURCEMOD_MM_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE"
MinimalRebuild="true" MinimalRebuild="true"
BasicRuntimeChecks="3" BasicRuntimeChecks="3"
RuntimeLibrary="1" RuntimeLibrary="1"
@ -118,7 +118,7 @@
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
AdditionalIncludeDirectories="..\interfaces;..\" AdditionalIncludeDirectories="..\interfaces;..\"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SOURCEMOD_MM_EXPORTS;_CRT_SECURE_NO_DEPRECATE" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SOURCEMOD_MM_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE"
RuntimeLibrary="0" RuntimeLibrary="0"
UsePrecompiledHeader="0" UsePrecompiledHeader="0"
WarningLevel="3" WarningLevel="3"
@ -182,6 +182,10 @@
RelativePath="..\CTextParsers.cpp" RelativePath="..\CTextParsers.cpp"
> >
</File> </File>
<File
RelativePath="..\sm_memtable.cpp"
>
</File>
<File <File
RelativePath="..\sourcemm_api.cpp" RelativePath="..\sourcemm_api.cpp"
> >
@ -204,6 +208,10 @@
RelativePath="..\sm_globals.h" RelativePath="..\sm_globals.h"
> >
</File> </File>
<File
RelativePath="..\sm_memtable.h"
>
</File>
<File <File
RelativePath="..\sm_platform.h" RelativePath="..\sm_platform.h"
> >
@ -247,6 +255,10 @@
RelativePath="..\systems\LibrarySys.h" RelativePath="..\systems\LibrarySys.h"
> >
</File> </File>
<File
RelativePath="..\systems\PluginInfoDatabase.h"
>
</File>
<File <File
RelativePath="..\systems\PluginSys.h" RelativePath="..\systems\PluginSys.h"
> >
@ -267,6 +279,10 @@
RelativePath="..\systems\LibrarySys.cpp" RelativePath="..\systems\LibrarySys.cpp"
> >
</File> </File>
<File
RelativePath="..\systems\PluginInfoDatabase.cpp"
>
</File>
<File <File
RelativePath="..\systems\PluginSys.cpp" RelativePath="..\systems\PluginSys.cpp"
> >

85
core/sm_memtable.cpp Normal file
View File

@ -0,0 +1,85 @@
#include <string.h>
#include <malloc.h>
#include "sm_memtable.h"
BaseMemTable::BaseMemTable(unsigned int init_size)
{
membase = (unsigned char *)malloc(init_size);
size = init_size;
}
BaseMemTable::~BaseMemTable()
{
free(membase);
membase = NULL;
}
int BaseMemTable::CreateMem(unsigned int addsize, void **addr)
{
int idx = (int)tail;
if (idx < 0)
{
return -1;
}
while (tail + addsize >= size)
{
size *= 2;
membase = (unsigned char *)realloc(membase, size);
}
tail += addsize;
if (addr)
{
*addr = (void *)&membase[idx];
}
return idx;
}
void *BaseMemTable::GetAddress(int index)
{
if (index < 0 || (unsigned int)index >= tail)
{
return NULL;
}
return &membase[index];
}
void BaseMemTable::Reset()
{
tail = 0;
}
BaseStringTable::BaseStringTable(unsigned int init_size) : m_table(init_size)
{
}
BaseStringTable::~BaseStringTable()
{
}
int BaseStringTable::AddString(const char *string)
{
size_t len = strlen(string) + 1;
int idx;
char *addr;
idx = m_table.CreateMem(len, (void **)&addr);
strcpy(addr, string);
return idx;
}
const char *BaseStringTable::GetString(int str)
{
return (const char *)m_table.GetAddress(str);
}
void BaseStringTable::Reset()
{
m_table.Reset();
}

69
core/sm_memtable.h Normal file
View File

@ -0,0 +1,69 @@
#ifndef _INCLUDE_SOURCEMOD_CORE_STRINGTABLE_H_
#define _INCLUDE_SOURCEMOD_CORE_STRINGTABLE_H_
class BaseMemTable
{
public:
BaseMemTable(unsigned int init_size);
~BaseMemTable();
public:
/**
* Allocates 'size' bytes of memory.
* Optionally outputs the address through 'addr'.
* Returns an index >= 0 on success, < 0 on failure.
*/
int CreateMem(unsigned int size, void **addr);
/**
* Given an index into the memory table, returns its address.
* Returns NULL if invalid.
*/
void *GetAddress(int index);
/**
* Scraps the memory table. For caching purposes, the memory
* is not freed, however subsequent calls to CreateMem() will
* begin at the first index again.
*/
void Reset();
private:
unsigned char *membase;
unsigned int size;
unsigned int tail;
};
class BaseStringTable
{
public:
BaseStringTable(unsigned int init_size);
~BaseStringTable();
public:
/**
* Adds a string to the string table and returns its index.
*/
int AddString(const char *string);
/**
* Given an index into the string table, returns the associated string.
*/
const char *GetString(int str);
/**
* Scraps the string table. For caching purposes, the memory
* is not freed, however subsequent calls to AddString() will
* begin at the first index again.
*/
void Reset();
/**
* Returns the parent BaseMemTable that this string table uses.
*/
inline BaseMemTable *GetMemTable()
{
return &m_table;
}
private:
BaseMemTable m_table;
};
#endif //_INCLUDE_SOURCEMOD_CORE_STRINGTABLE_H_

View File

@ -13,6 +13,7 @@
#if !defined snprintf #if !defined snprintf
#define snprintf _snprintf #define snprintf _snprintf
#endif #endif
#define strcasecmp strcmpi
#include <windows.h> #include <windows.h>
#include <direct.h> #include <direct.h>
#define PLATFORM_LIB_EXT "dll" #define PLATFORM_LIB_EXT "dll"

View File

@ -0,0 +1,266 @@
#include <stdarg.h>
#include <string.h>
#include "PluginInfoDatabase.h"
#include "PluginSys.h"
void PluginSettings::Init()
{
name = -1;
pause_val = false;
type_val = PluginType_MapUpdated;
optarray = -1;
opts_num = 0;
opts_size = 0;
}
/**
* :TODO: write the logger, make these errors log instead of being static
* NOTE: once we do that, we will have to change some code to ignore sections
*/
CPluginInfoDatabase::CPluginInfoDatabase()
{
m_strtab = NULL;
m_infodb_count = 0;
m_infodb_size = 0;
m_infodb = -1;
}
CPluginInfoDatabase::~CPluginInfoDatabase()
{
delete m_strtab;
}
void CPluginInfoDatabase::ReadSMC_ParseStart()
{
/* Create or reset our string table */
if (m_strtab)
{
m_strtab->Reset();
} else {
m_strtab = new BaseStringTable(1024);
}
/* Set our internal states to the beginning */
in_plugins = false;
cur_plugin = -1;
in_options = false;
}
SMCParseResult CPluginInfoDatabase::MakeError(const char *fmt, ...)
{
char buffer[512];
va_list ap;
va_start(ap, fmt);
vsnprintf(buffer, sizeof(buffer), fmt, ap);
va_end(ap);
m_errmsg = m_strtab->AddString(buffer);
return SMCParse_HaltFail;
}
unsigned int CPluginInfoDatabase::GetSettingsNum()
{
return m_infodb_count;
}
PluginSettings *CPluginInfoDatabase::GetSettingsIfMatch(unsigned int index, const char *filename)
{
BaseMemTable *memtab = m_strtab->GetMemTable();
PluginSettings *table = (PluginSettings *)memtab->GetAddress(m_infodb);
if (!table || index >= m_infodb_count)
{
return NULL;
}
const char *name = m_strtab->GetString(table[index].name);
if (!name)
{
return NULL;
}
if (!g_PluginMngr.TestAliasMatch(name, filename))
{
return NULL;
}
return &table[index];
}
void CPluginInfoDatabase::GetOptionsForPlugin(PluginSettings *settings, unsigned int opt_num, const char **key, const char **val)
{
PluginOpts *table = (PluginOpts *)m_strtab->GetMemTable()->GetAddress(settings->optarray);
if (!table)
{
*key = NULL;
*val = NULL;
return;
}
if (opt_num >= settings->opts_num)
{
*key = NULL;
*val = NULL;
return;
}
*key = m_strtab->GetString(table[opt_num].key);
*val = m_strtab->GetString(table[opt_num].val);
}
SMCParseResult CPluginInfoDatabase::ReadSMC_KeyValue(const char *key,
const char *value,
bool key_quotes,
bool value_quotes)
{
if (cur_plugin != -1)
{
PluginSettings *plugin = (PluginSettings *)m_strtab->GetMemTable()->GetAddress(cur_plugin);
if (!in_options)
{
if (strcmp(key, "pause") == 0)
{
if (strcasecmp(value, "yes") == 0)
{
plugin->pause_val = true;
} else {
plugin->pause_val = false;
}
} else if (strcmp(key, "lifetime") == 0) {
if (strcasecmp(value, "private") == 0)
{
plugin->type_val = PluginType_Private;
} else if (strcasecmp(value, "mapsync") == 0) {
plugin->type_val = PluginType_MapUpdated;
} else if (strcasecmp(value, "maponly") == 0) {
plugin->type_val = PluginType_MapOnly;
} else if (strcasecmp(value, "global") == 0) {
plugin->type_val = PluginType_Global;
} else {
return MakeError("Unknown value for key \"lifetime\": \"%s\"", value);
}
} else {
return MakeError("Unknown property key: \"%s\"", key);
}
} else {
/* Cache every option, valid or not */
int keyidx = m_strtab->AddString(key);
int validx = m_strtab->AddString(value);
PluginOpts *table;
BaseMemTable *memtab = m_strtab->GetMemTable();
if (plugin->opts_num + 1 > plugin->opts_size)
{
unsigned int oldsize = plugin->opts_size;
if (oldsize == 0)
{
//right now we don't have many
plugin->opts_size = 2;
} else {
plugin->opts_size *= 2;
}
int newidx = memtab->CreateMem(plugin->opts_size * sizeof(PluginOpts), (void **)&table);
if (plugin->optarray != -1)
{
void *oldtable = memtab->GetAddress(plugin->optarray);
memcpy(table, oldtable, oldsize * sizeof(PluginOpts));
}
plugin->optarray = newidx;
} else {
table = (PluginOpts *)memtab->GetAddress(plugin->optarray);
}
PluginOpts *opt = &table[plugin->opts_num++];
opt->key = keyidx;
opt->val = validx;
}
} else if (in_plugins) {
return MakeError("Unknown property key: \"%s\"", key);
} else {
/* Ignore anything we don't know about! */
}
return SMCParse_Continue;
}
SMCParseResult CPluginInfoDatabase::ReadSMC_LeavingSection()
{
if (in_plugins)
{
if (cur_plugin == -1)
{
if (in_options)
{
in_options = false;
} else {
/* If the plugin is ending, add it to the table */
BaseMemTable *memtab = m_strtab->GetMemTable();
int *table;
if (m_infodb_count + 1 > m_infodb_size)
{
unsigned int oldsize = m_infodb_size;
if (!m_infodb_size)
{
m_infodb_size = 8;
} else {
m_infodb_size *= 2;
}
int newidx = memtab->CreateMem(m_infodb_size, (void **)&table);
if (m_infodb != -1)
{
void *oldtable = (int *)memtab->GetAddress(m_infodb);
memcpy(table, oldtable, oldsize * sizeof(int));
}
m_infodb = newidx;
} else {
table = (int *)memtab->GetAddress(m_infodb);
}
/* Assign to table and scrap the current plugin */
table[m_infodb_count++] = cur_plugin;
cur_plugin = -1;
}
} else {
in_plugins = false;
}
}
return SMCParse_Continue;
}
SMCParseResult CPluginInfoDatabase::ReadSMC_NewSection(const char *name, bool opt_quotes)
{
if (!in_plugins)
{
/* If we're not in the main Plugins section, and we don't get it for the name, error out */
if (strcmp(name, "Plugins") != 0)
{
return MakeError("Unknown root section: \"%s\"", name);
} else {
/* Otherwise set our states */
in_plugins = true;
cur_plugin = -1;
in_options = false;
}
} else {
if (cur_plugin == -1)
{
/* If we get a plugin node and we don't have a current plugin, create a new one */
PluginSettings *plugin;
cur_plugin = m_strtab->GetMemTable()->CreateMem(sizeof(PluginSettings), (void **)&plugin);
plugin->Init();
plugin->name = m_strtab->AddString(name);
in_options = false;
} else {
if (!in_options && strcmp(name, "Options") == 0)
{
in_options = true;
} else {
return MakeError("Unknown plugin sub-section: \"%s\"", name);
}
}
}
return SMCParse_Continue;
}

View File

@ -0,0 +1,74 @@
#ifndef _INCLUDE_SOURCEMOD_CORE_SYSTEM_PLUGININFODATABASE_H_
#define _INCLUDE_SOURCEMOD_CORE_SYSTEM_PLUGININFODATABASE_H_
/**
* This file parses plugin_settings.cfg and stores the information in cached memory.
* It provides simplistic abstraction to retrieving the info.
* :TODO: currently untested
*/
#include "sm_memtable.h"
#include "ITextParsers.h"
#include "IPluginSys.h"
#include "sm_globals.h"
struct PluginOpts
{
int key;
int val;
};
struct PluginSettings
{
void Init();
int name;
bool pause_val;
PluginType type_val;
int optarray;
size_t opts_num;
size_t opts_size;
};
class CPluginInfoDatabase : public ITextListener_SMC
{
public:
CPluginInfoDatabase();
~CPluginInfoDatabase();
public: //ITextListener_SMC
void ReadSMC_ParseStart();
SMCParseResult ReadSMC_NewSection(const char *name, bool opt_quotes);
SMCParseResult ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes);
SMCParseResult ReadSMC_LeavingSection();
public:
/**
* Returns the number of plugin settings available.
*/
unsigned int GetSettingsNum();
/**
* Given an index, returns the plugin settings block if the filename matches.
* Otherwise, returns NULL.
*/
PluginSettings *GetSettingsIfMatch(unsigned int index, const char *filename);
/**
* Given a plugin settings struct and an index,
* returns the given JIT key/value option pair at that index.
* If the input is invalid, key and val will be set to NULL.
*/
void GetOptionsForPlugin(PluginSettings *settings, unsigned int opt_num, const char **key, const char **val);
private:
SMCParseResult MakeError(const char *fmt, ...);
private:
BaseStringTable *m_strtab;
int m_errmsg;
bool in_plugins;
bool in_options;
unsigned int m_infodb;
size_t m_infodb_count;
size_t m_infodb_size;
int cur_plugin;
};
#endif //_INCLUDE_SOURCEMOD_CORE_SYSTEM_PLUGININFODATABASE_H_

View File

@ -2,6 +2,7 @@
#include "PluginSys.h" #include "PluginSys.h"
#include "LibrarySys.h" #include "LibrarySys.h"
#include "sourcemm_api.h" #include "sourcemm_api.h"
#include "CTextParsers.h"
CPluginManager g_PluginMngr; CPluginManager g_PluginMngr;
@ -288,9 +289,19 @@ void CPluginManager::CPluginIterator::Reset()
* PLUGIN MANAGER * * PLUGIN MANAGER *
******************/ ******************/
void CPluginManager::RefreshOrLoadPlugins(const char *basedir) void CPluginManager::RefreshOrLoadPlugins(const char *config, const char *basedir)
{ {
IDirectory *dir = g_LibSys.OpenDirectory(basedir); /* First read in the database of plugin settings */
SMCParseError err;
unsigned int line, col;
if ((err=g_TextParse.ParseFile_SMC(config, &m_PluginInfo, &line, &col)) != SMCParse_Okay)
{
/* :TODO: log the error, don't bail out though */
}
//:TODO: move this to a separate recursive function and do stuff
/*IDirectory *dir = g_LibSys.OpenDirectory(basedir);
while (dir->MoreFiles()) while (dir->MoreFiles())
{ {
if (dir->IsEntryDirectory() && (strcmp(dir->GetEntryName(), "disabled") != 0)) if (dir->IsEntryDirectory() && (strcmp(dir->GetEntryName(), "disabled") != 0))
@ -300,7 +311,7 @@ void CPluginManager::RefreshOrLoadPlugins(const char *basedir)
RefreshOrLoadPlugins(basedir); RefreshOrLoadPlugins(basedir);
} }
} }
g_LibSys.CloseDirectory(dir); g_LibSys.CloseDirectory(dir);*/
} }
IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType type, char error[], size_t err_max) IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType type, char error[], size_t err_max)
@ -446,6 +457,215 @@ CFunction *CPluginManager::GetFunctionFromPool(funcid_t f, CPlugin *plugin)
} }
} }
bool CPluginManager::TestAliasMatch(const char *alias, const char *localpath)
{
/* As an optimization, we do not call strlen, but compute the length in the first pass */
size_t alias_len = 0;
size_t local_len = 0;
const char *ptr = alias;
unsigned int alias_explicit_paths = 0;
unsigned int alias_path_end = 0;
while (*ptr != '\0')
{
if (*ptr == '\\' || *ptr == '/')
{
alias_explicit_paths++;
alias_path_end = alias_len;
}
alias_len++;
ptr++;
}
if (alias_path_end == alias_len - 1)
{
/* Trailing slash is totally invalid here */
return false;
}
ptr = localpath;
unsigned int local_explicit_paths = 0;
unsigned int local_path_end = 0;
while (*ptr != '\0')
{
if (*ptr == '\\' || *ptr == '/')
{
local_explicit_paths++;
local_path_end = local_len;
}
local_len++;
ptr++;
}
/* If the alias has more explicit paths than the real path,
* no match will be possible.
*/
if (alias_explicit_paths > local_explicit_paths)
{
return false;
}
if (alias_explicit_paths)
{
/* We need to find if the paths match now. For example, these should all match:
* csdm csdm
* csdm optional/csdm
* csdm/ban optional/crab/csdm/ban
*/
const char *aliasptr = alias;
const char *localptr = localpath;
bool match = true;
do
{
if (*aliasptr != *localptr)
{
/* We have to knock one path off */
local_explicit_paths--;
if (alias_explicit_paths > local_explicit_paths)
{
/* Skip out if we're gonna have an impossible match */
return false;
}
/* Eat up localptr tokens until we get a result */
while (((localptr - localpath) < (int)local_path_end)
&& *localptr != '/'
&& *localptr != '\\')
{
localptr++;
}
/* Check if we hit the end of our searchable area.
* This probably isn't possible because of the path
* count check, but it's a good idea anyway.
*/
if ((localptr - localpath) >= (int)local_path_end)
{
return false;
} else {
/* Consume the slash token */
localptr++;
}
/* Reset the alias pointer so we can continue consuming */
aliasptr = alias;
match = false;
continue;
}
/* Note:
* This is safe because if localptr terminates early, aliasptr will too
*/
do
{
/* We should never reach the end of the string because of this check. */
bool aliasend = (aliasptr - alias) > (int)alias_path_end;
bool localend = (localptr - localpath) > (int)local_path_end;
if (aliasend || localend)
{
if (aliasend && localend)
{
/* we matched, and we can break out now */
match = true;
break;
}
/* Otherwise, we've hit the end somehow and rest won't match up. Break out. */
match = false;
break;
}
/* If we got here, it's safe to compare the next two tokens */
if (*localptr != *aliasptr)
{
match = false;
break;
}
localptr++;
aliasptr++;
} while (true);
} while (!match);
}
/* If we got here, it's time to compare filenames */
const char *aliasptr = alias;
const char *localptr = localpath;
if (alias_explicit_paths)
{
aliasptr = &alias[alias_path_end + 1];
}
if (local_explicit_paths)
{
localptr = &localpath[local_path_end + 1];
}
while (true)
{
if (*aliasptr == '*')
{
/* First, see if this is the last character */
if (aliasptr - alias == alias_len - 1)
{
/* If so, there's no need to match anything else */
return true;
}
/* Otherwise, we need to search for an appropriate matching sequence in local.
* Note that we only need to search up to the next asterisk.
*/
aliasptr++;
bool match = true;
const char *local_orig = localptr;
do
{
match = true;
while (*aliasptr != '\0' && *aliasptr != '*')
{
/* Since aliasptr is never '\0', localptr hitting the end will fail */
if (*aliasptr != *localptr)
{
match = false;
break;
}
aliasptr++;
localptr++;
}
if (!match)
{
/* If we didn't get a match, we need to advance the search stream.
* This will let us skip tokens while still searching for another match.
*/
localptr = ++local_orig;
/* Make sure we don't go out of bounds */
if (*localptr == '\0')
{
break;
}
}
} while (!match);
if (!match)
{
return false;
} else {
/* If we got a match, move on to the next token */
continue;
}
} else if (*aliasptr == '\0') {
if (*localptr == '\0'
||
strcmp(localptr, ".smx") == 0)
{
return true;
} else {
return false;
}
} else if (*aliasptr != *localptr) {
return false;
}
aliasptr++;
localptr++;
}
return true;
}
CPluginManager::~CPluginManager() CPluginManager::~CPluginManager()
{ {
//:TODO: we need a good way to free what we're holding //:TODO: we need a good way to free what we're holding

View File

@ -6,6 +6,7 @@
#include <sh_stack.h> #include <sh_stack.h>
#include "sm_globals.h" #include "sm_globals.h"
#include "CFunction.h" #include "CFunction.h"
#include "PluginInfoDatabase.h"
using namespace SourceHook; using namespace SourceHook;
@ -60,6 +61,13 @@ private:
CFunction **m_pub_funcs; CFunction **m_pub_funcs;
}; };
struct PluginDBInfo
{
bool pause;
PluginType lifetime;
};
class CPluginManager : public IPluginManager class CPluginManager : public IPluginManager
{ {
friend class CPlugin; friend class CPlugin;
@ -67,6 +75,7 @@ public:
CPluginManager(); CPluginManager();
~CPluginManager(); ~CPluginManager();
public: public:
/* Implements iterator class */
class CPluginIterator : public IPluginIterator class CPluginIterator : public IPluginIterator
{ {
public: public:
@ -83,7 +92,7 @@ public:
List<IPlugin *>::iterator current; List<IPlugin *>::iterator current;
}; };
friend class CPluginManager::CPluginIterator; friend class CPluginManager::CPluginIterator;
public: public: //IPluginManager
virtual IPlugin *LoadPlugin(const char *path, virtual IPlugin *LoadPlugin(const char *path,
bool debug, bool debug,
PluginType type, PluginType type,
@ -96,7 +105,21 @@ public:
virtual void AddPluginsListener(IPluginsListener *listener); virtual void AddPluginsListener(IPluginsListener *listener);
virtual void RemovePluginsListener(IPluginsListener *listener); virtual void RemovePluginsListener(IPluginsListener *listener);
public: public:
virtual void RefreshOrLoadPlugins(const char *basedir); /**
* Refreshes and loads plugins, usually used on mapchange
*/
virtual void RefreshOrLoadPlugins(const char *config, const char *basedir);
/**
* Tests a plugin file mask against a local folder.
* The alias is searched backwards from localdir - i.e., given this input:
* csdm/ban csdm/ban
* ban csdm/ban
* csdm/ban optional/csdm/ban
* All of these will return true for an alias match.
* Wildcards are allowed in the filename.
*/
virtual bool TestAliasMatch(const char *alias, const char *localdir);
protected: protected:
void ReleaseIterator(CPluginIterator *iter); void ReleaseIterator(CPluginIterator *iter);
CFunction *GetFunctionFromPool(funcid_t f, CPlugin *plugin); CFunction *GetFunctionFromPool(funcid_t f, CPlugin *plugin);
@ -106,6 +129,7 @@ private:
List<IPlugin *> m_plugins; List<IPlugin *> m_plugins;
CStack<CPluginManager::CPluginIterator *> m_iters; CStack<CPluginManager::CPluginIterator *> m_iters;
CStack<CFunction *> m_funcpool; CStack<CFunction *> m_funcpool;
CPluginInfoDatabase m_PluginInfo;
}; };
extern CPluginManager g_PluginMngr; extern CPluginManager g_PluginMngr;