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:
parent
f807575429
commit
a1e58aa9ef
@ -587,6 +587,8 @@ failed:
|
||||
*line = curline;
|
||||
}
|
||||
|
||||
smc->ReadSMC_ParseEnd(true, (err == SMCParse_Custom));
|
||||
|
||||
if (col)
|
||||
{
|
||||
*col = curtok;
|
||||
|
@ -41,7 +41,7 @@
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
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"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
@ -118,7 +118,7 @@
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
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"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
@ -182,6 +182,10 @@
|
||||
RelativePath="..\CTextParsers.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\sm_memtable.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\sourcemm_api.cpp"
|
||||
>
|
||||
@ -204,6 +208,10 @@
|
||||
RelativePath="..\sm_globals.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\sm_memtable.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\sm_platform.h"
|
||||
>
|
||||
@ -247,6 +255,10 @@
|
||||
RelativePath="..\systems\LibrarySys.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\systems\PluginInfoDatabase.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\systems\PluginSys.h"
|
||||
>
|
||||
@ -267,6 +279,10 @@
|
||||
RelativePath="..\systems\LibrarySys.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\systems\PluginInfoDatabase.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\systems\PluginSys.cpp"
|
||||
>
|
||||
|
85
core/sm_memtable.cpp
Normal file
85
core/sm_memtable.cpp
Normal 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
69
core/sm_memtable.h
Normal 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_
|
@ -13,6 +13,7 @@
|
||||
#if !defined snprintf
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
#define strcasecmp strcmpi
|
||||
#include <windows.h>
|
||||
#include <direct.h>
|
||||
#define PLATFORM_LIB_EXT "dll"
|
||||
|
266
core/systems/PluginInfoDatabase.cpp
Normal file
266
core/systems/PluginInfoDatabase.cpp
Normal 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;
|
||||
}
|
74
core/systems/PluginInfoDatabase.h
Normal file
74
core/systems/PluginInfoDatabase.h
Normal 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_
|
@ -2,6 +2,7 @@
|
||||
#include "PluginSys.h"
|
||||
#include "LibrarySys.h"
|
||||
#include "sourcemm_api.h"
|
||||
#include "CTextParsers.h"
|
||||
|
||||
CPluginManager g_PluginMngr;
|
||||
|
||||
@ -288,9 +289,19 @@ void CPluginManager::CPluginIterator::Reset()
|
||||
* 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())
|
||||
{
|
||||
if (dir->IsEntryDirectory() && (strcmp(dir->GetEntryName(), "disabled") != 0))
|
||||
@ -300,7 +311,7 @@ void CPluginManager::RefreshOrLoadPlugins(const char *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)
|
||||
@ -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()
|
||||
{
|
||||
//:TODO: we need a good way to free what we're holding
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <sh_stack.h>
|
||||
#include "sm_globals.h"
|
||||
#include "CFunction.h"
|
||||
#include "PluginInfoDatabase.h"
|
||||
|
||||
using namespace SourceHook;
|
||||
|
||||
@ -60,6 +61,13 @@ private:
|
||||
CFunction **m_pub_funcs;
|
||||
};
|
||||
|
||||
struct PluginDBInfo
|
||||
{
|
||||
bool pause;
|
||||
PluginType lifetime;
|
||||
|
||||
};
|
||||
|
||||
class CPluginManager : public IPluginManager
|
||||
{
|
||||
friend class CPlugin;
|
||||
@ -67,6 +75,7 @@ public:
|
||||
CPluginManager();
|
||||
~CPluginManager();
|
||||
public:
|
||||
/* Implements iterator class */
|
||||
class CPluginIterator : public IPluginIterator
|
||||
{
|
||||
public:
|
||||
@ -83,7 +92,7 @@ public:
|
||||
List<IPlugin *>::iterator current;
|
||||
};
|
||||
friend class CPluginManager::CPluginIterator;
|
||||
public:
|
||||
public: //IPluginManager
|
||||
virtual IPlugin *LoadPlugin(const char *path,
|
||||
bool debug,
|
||||
PluginType type,
|
||||
@ -96,7 +105,21 @@ public:
|
||||
virtual void AddPluginsListener(IPluginsListener *listener);
|
||||
virtual void RemovePluginsListener(IPluginsListener *listener);
|
||||
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:
|
||||
void ReleaseIterator(CPluginIterator *iter);
|
||||
CFunction *GetFunctionFromPool(funcid_t f, CPlugin *plugin);
|
||||
@ -106,6 +129,7 @@ private:
|
||||
List<IPlugin *> m_plugins;
|
||||
CStack<CPluginManager::CPluginIterator *> m_iters;
|
||||
CStack<CFunction *> m_funcpool;
|
||||
CPluginInfoDatabase m_PluginInfo;
|
||||
};
|
||||
|
||||
extern CPluginManager g_PluginMngr;
|
||||
|
Loading…
Reference in New Issue
Block a user