initial import of plugin database (UNTESTED)
authorDavid Anderson <dvander@alliedmods.net>
Sun Dec 10 09:19:59 2006 +0000 (2006-12-10)
changeset 203c7f86f9e6f60
parent 202 8824cfb203ac
child 204 947d19d39772
initial import of plugin database (UNTESTED)
added file pattern matching routine (TESTED)
added memtable caching (UNTESTED)
core/CTextParsers.cpp
core/msvc8/sourcemod_mm.vcproj
core/sm_memtable.cpp
core/sm_memtable.h
core/sm_platform.h
core/systems/PluginInfoDatabase.cpp
core/systems/PluginInfoDatabase.h
core/systems/PluginSys.cpp
core/systems/PluginSys.h
     1.1 --- a/core/CTextParsers.cpp	Sat Dec 09 03:18:48 2006 +0000
     1.2 +++ b/core/CTextParsers.cpp	Sun Dec 10 09:19:59 2006 +0000
     1.3 @@ -587,6 +587,8 @@
     1.4  		*line = curline;
     1.5  	}
     1.6  
     1.7 +	smc->ReadSMC_ParseEnd(true, (err == SMCParse_Custom));
     1.8 +
     1.9  	if (col)
    1.10  	{
    1.11  		*col = curtok;
     2.1 --- a/core/msvc8/sourcemod_mm.vcproj	Sat Dec 09 03:18:48 2006 +0000
     2.2 +++ b/core/msvc8/sourcemod_mm.vcproj	Sun Dec 10 09:19:59 2006 +0000
     2.3 @@ -41,7 +41,7 @@
     2.4  				Name="VCCLCompilerTool"
     2.5  				Optimization="0"
     2.6  				AdditionalIncludeDirectories="..\interfaces;..\;..\systems;..\..\sourcepawn\include"
     2.7 -				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SOURCEMOD_MM_EXPORTS;_CRT_SECURE_NO_DEPRECATE"
     2.8 +				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SOURCEMOD_MM_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE"
     2.9  				MinimalRebuild="true"
    2.10  				BasicRuntimeChecks="3"
    2.11  				RuntimeLibrary="1"
    2.12 @@ -118,7 +118,7 @@
    2.13  			<Tool
    2.14  				Name="VCCLCompilerTool"
    2.15  				AdditionalIncludeDirectories="..\interfaces;..\"
    2.16 -				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SOURCEMOD_MM_EXPORTS;_CRT_SECURE_NO_DEPRECATE"
    2.17 +				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SOURCEMOD_MM_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE"
    2.18  				RuntimeLibrary="0"
    2.19  				UsePrecompiledHeader="0"
    2.20  				WarningLevel="3"
    2.21 @@ -183,6 +183,10 @@
    2.22  				>
    2.23  			</File>
    2.24  			<File
    2.25 +				RelativePath="..\sm_memtable.cpp"
    2.26 +				>
    2.27 +			</File>
    2.28 +			<File
    2.29  				RelativePath="..\sourcemm_api.cpp"
    2.30  				>
    2.31  			</File>
    2.32 @@ -205,6 +209,10 @@
    2.33  				>
    2.34  			</File>
    2.35  			<File
    2.36 +				RelativePath="..\sm_memtable.h"
    2.37 +				>
    2.38 +			</File>
    2.39 +			<File
    2.40  				RelativePath="..\sm_platform.h"
    2.41  				>
    2.42  			</File>
    2.43 @@ -248,6 +256,10 @@
    2.44  					>
    2.45  				</File>
    2.46  				<File
    2.47 +					RelativePath="..\systems\PluginInfoDatabase.h"
    2.48 +					>
    2.49 +				</File>
    2.50 +				<File
    2.51  					RelativePath="..\systems\PluginSys.h"
    2.52  					>
    2.53  				</File>
    2.54 @@ -268,6 +280,10 @@
    2.55  					>
    2.56  				</File>
    2.57  				<File
    2.58 +					RelativePath="..\systems\PluginInfoDatabase.cpp"
    2.59 +					>
    2.60 +				</File>
    2.61 +				<File
    2.62  					RelativePath="..\systems\PluginSys.cpp"
    2.63  					>
    2.64  				</File>
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/core/sm_memtable.cpp	Sun Dec 10 09:19:59 2006 +0000
     3.3 @@ -0,0 +1,85 @@
     3.4 +#include <string.h>
     3.5 +#include <malloc.h>
     3.6 +#include "sm_memtable.h"
     3.7 +
     3.8 +BaseMemTable::BaseMemTable(unsigned int init_size)
     3.9 +{
    3.10 +	membase = (unsigned char *)malloc(init_size);
    3.11 +	size = init_size;
    3.12 +}
    3.13 +
    3.14 +BaseMemTable::~BaseMemTable()
    3.15 +{
    3.16 +	free(membase);
    3.17 +	membase = NULL;
    3.18 +}
    3.19 +
    3.20 +int BaseMemTable::CreateMem(unsigned int addsize, void **addr)
    3.21 +{
    3.22 +	int idx = (int)tail;
    3.23 +
    3.24 +	if (idx < 0)
    3.25 +	{
    3.26 +		return -1;
    3.27 +	}
    3.28 +
    3.29 +	while (tail + addsize >= size)
    3.30 +	{
    3.31 +		size *= 2;
    3.32 +		membase = (unsigned char *)realloc(membase, size);
    3.33 +	}
    3.34 +
    3.35 +	tail += addsize;
    3.36 +
    3.37 +	if (addr)
    3.38 +	{
    3.39 +		*addr = (void *)&membase[idx];
    3.40 +	}
    3.41 +
    3.42 +	return idx;
    3.43 +}
    3.44 +
    3.45 +void *BaseMemTable::GetAddress(int index)
    3.46 +{
    3.47 +	if (index < 0 || (unsigned int)index >= tail)
    3.48 +	{
    3.49 +		return NULL;
    3.50 +	}
    3.51 +
    3.52 +	return &membase[index];
    3.53 +}
    3.54 +
    3.55 +void BaseMemTable::Reset()
    3.56 +{
    3.57 +	tail = 0;
    3.58 +}
    3.59 +
    3.60 +BaseStringTable::BaseStringTable(unsigned int init_size) : m_table(init_size)
    3.61 +{
    3.62 +}
    3.63 +
    3.64 +BaseStringTable::~BaseStringTable()
    3.65 +{
    3.66 +}
    3.67 +
    3.68 +int BaseStringTable::AddString(const char *string)
    3.69 +{
    3.70 +	size_t len = strlen(string) + 1;
    3.71 +	int idx;
    3.72 +	char *addr;
    3.73 +
    3.74 +	idx = m_table.CreateMem(len, (void **)&addr);
    3.75 +	strcpy(addr, string);
    3.76 +
    3.77 +	return idx;
    3.78 +}
    3.79 +
    3.80 +const char *BaseStringTable::GetString(int str)
    3.81 +{
    3.82 +	return (const char *)m_table.GetAddress(str);
    3.83 +}
    3.84 +
    3.85 +void BaseStringTable::Reset()
    3.86 +{
    3.87 +	m_table.Reset();
    3.88 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/core/sm_memtable.h	Sun Dec 10 09:19:59 2006 +0000
     4.3 @@ -0,0 +1,69 @@
     4.4 +#ifndef _INCLUDE_SOURCEMOD_CORE_STRINGTABLE_H_
     4.5 +#define _INCLUDE_SOURCEMOD_CORE_STRINGTABLE_H_
     4.6 +
     4.7 +class BaseMemTable
     4.8 +{
     4.9 +public:
    4.10 +	BaseMemTable(unsigned int init_size);
    4.11 +	~BaseMemTable();
    4.12 +public:
    4.13 +	/**
    4.14 +	 * Allocates 'size' bytes of memory.
    4.15 +	 * Optionally outputs the address through 'addr'.
    4.16 +	 * Returns an index >= 0 on success, < 0 on failure.
    4.17 +	 */
    4.18 +	int CreateMem(unsigned int size, void **addr);
    4.19 +
    4.20 +	/**
    4.21 +	 * Given an index into the memory table, returns its address.
    4.22 +	 * Returns NULL if invalid.
    4.23 +	 */
    4.24 +	void *GetAddress(int index);
    4.25 +
    4.26 +	/**
    4.27 +	 * Scraps the memory table.  For caching purposes, the memory 
    4.28 +	 * is not freed, however subsequent calls to CreateMem() will 
    4.29 +	 * begin at the first index again.
    4.30 +	 */
    4.31 +	void Reset();
    4.32 +private:
    4.33 +	unsigned char *membase;
    4.34 +	unsigned int size;
    4.35 +	unsigned int tail;
    4.36 +};
    4.37 +
    4.38 +class BaseStringTable
    4.39 +{
    4.40 +public:
    4.41 +	BaseStringTable(unsigned int init_size);
    4.42 +	~BaseStringTable();
    4.43 +public:
    4.44 +	/** 
    4.45 +	 * Adds a string to the string table and returns its index.
    4.46 +	 */
    4.47 +	int AddString(const char *string);
    4.48 +
    4.49 +	/**
    4.50 +	 * Given an index into the string table, returns the associated string.
    4.51 +	 */
    4.52 +	const char *GetString(int str);
    4.53 +
    4.54 +	/**
    4.55 +	 * Scraps the string table.  For caching purposes, the memory
    4.56 +	 * is not freed, however subsequent calls to AddString() will 
    4.57 +	 * begin at the first index again.
    4.58 +	 */
    4.59 +	void Reset();
    4.60 +
    4.61 +	/**
    4.62 +	 * Returns the parent BaseMemTable that this string table uses.
    4.63 +	 */
    4.64 +	inline BaseMemTable *GetMemTable()
    4.65 +	{
    4.66 +		return &m_table;
    4.67 +	}
    4.68 +private:
    4.69 +	BaseMemTable m_table;
    4.70 +};
    4.71 +
    4.72 +#endif //_INCLUDE_SOURCEMOD_CORE_STRINGTABLE_H_
     5.1 --- a/core/sm_platform.h	Sat Dec 09 03:18:48 2006 +0000
     5.2 +++ b/core/sm_platform.h	Sun Dec 10 09:19:59 2006 +0000
     5.3 @@ -13,6 +13,7 @@
     5.4  #if !defined snprintf
     5.5  #define snprintf _snprintf
     5.6  #endif
     5.7 +#define strcasecmp strcmpi
     5.8  #include <windows.h>
     5.9  #include <direct.h>
    5.10  #define PLATFORM_LIB_EXT		"dll"
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/core/systems/PluginInfoDatabase.cpp	Sun Dec 10 09:19:59 2006 +0000
     6.3 @@ -0,0 +1,266 @@
     6.4 +#include <stdarg.h>
     6.5 +#include <string.h>
     6.6 +#include "PluginInfoDatabase.h"
     6.7 +#include "PluginSys.h"
     6.8 +
     6.9 +void PluginSettings::Init()
    6.10 +{
    6.11 +	name = -1;
    6.12 +	pause_val = false;
    6.13 +	type_val = PluginType_MapUpdated;
    6.14 +	optarray = -1;
    6.15 +	opts_num = 0;
    6.16 +	opts_size = 0;
    6.17 +}
    6.18 +
    6.19 +/**
    6.20 + * :TODO: write the logger, make these errors log instead of being static
    6.21 + * NOTE: once we do that, we will have to change some code to ignore sections
    6.22 + */
    6.23 +
    6.24 +CPluginInfoDatabase::CPluginInfoDatabase()
    6.25 +{
    6.26 +	m_strtab = NULL;
    6.27 +	m_infodb_count = 0;
    6.28 +	m_infodb_size = 0;
    6.29 +	m_infodb = -1;
    6.30 +}
    6.31 +
    6.32 +CPluginInfoDatabase::~CPluginInfoDatabase()
    6.33 +{
    6.34 +	delete m_strtab;
    6.35 +}
    6.36 +
    6.37 +void CPluginInfoDatabase::ReadSMC_ParseStart()
    6.38 +{
    6.39 +	/* Create or reset our string table */
    6.40 +	if (m_strtab)
    6.41 +	{
    6.42 +		m_strtab->Reset();
    6.43 +	} else {
    6.44 +		m_strtab = new BaseStringTable(1024);
    6.45 +	}
    6.46 +
    6.47 +	/* Set our internal states to the beginning */
    6.48 +	in_plugins = false;
    6.49 +	cur_plugin = -1;
    6.50 +	in_options = false;
    6.51 +}
    6.52 +
    6.53 +SMCParseResult CPluginInfoDatabase::MakeError(const char *fmt, ...)
    6.54 +{
    6.55 +	char buffer[512];
    6.56 +	va_list ap;
    6.57 +
    6.58 +	va_start(ap, fmt);
    6.59 +	vsnprintf(buffer, sizeof(buffer), fmt, ap);
    6.60 +	va_end(ap);
    6.61 +
    6.62 +	m_errmsg = m_strtab->AddString(buffer);
    6.63 +
    6.64 +	return SMCParse_HaltFail;
    6.65 +}
    6.66 +
    6.67 +unsigned int CPluginInfoDatabase::GetSettingsNum()
    6.68 +{
    6.69 +	return m_infodb_count;
    6.70 +}
    6.71 +
    6.72 +PluginSettings *CPluginInfoDatabase::GetSettingsIfMatch(unsigned int index, const char *filename)
    6.73 +{
    6.74 +	BaseMemTable *memtab = m_strtab->GetMemTable();
    6.75 +	PluginSettings *table = (PluginSettings *)memtab->GetAddress(m_infodb);
    6.76 +
    6.77 +	if (!table || index >= m_infodb_count)
    6.78 +	{
    6.79 +		return NULL;
    6.80 +	}
    6.81 +
    6.82 +	const char *name = m_strtab->GetString(table[index].name);
    6.83 +
    6.84 +	if (!name)
    6.85 +	{
    6.86 +		return NULL;
    6.87 +	}
    6.88 +
    6.89 +	if (!g_PluginMngr.TestAliasMatch(name, filename))
    6.90 +	{
    6.91 +		return NULL;
    6.92 +	}
    6.93 +
    6.94 +	return &table[index];
    6.95 +}
    6.96 +
    6.97 +void CPluginInfoDatabase::GetOptionsForPlugin(PluginSettings *settings, unsigned int opt_num, const char **key, const char **val)
    6.98 +{
    6.99 +	PluginOpts *table = (PluginOpts *)m_strtab->GetMemTable()->GetAddress(settings->optarray);
   6.100 +	if (!table)
   6.101 +	{
   6.102 +		*key = NULL;
   6.103 +		*val = NULL;
   6.104 +		return;
   6.105 +	}
   6.106 +
   6.107 +	if (opt_num >= settings->opts_num)
   6.108 +	{
   6.109 +		*key = NULL;
   6.110 +		*val = NULL;
   6.111 +		return;
   6.112 +	}
   6.113 +
   6.114 +	*key = m_strtab->GetString(table[opt_num].key);
   6.115 +	*val = m_strtab->GetString(table[opt_num].val);
   6.116 +}
   6.117 +
   6.118 +SMCParseResult CPluginInfoDatabase::ReadSMC_KeyValue(const char *key, 
   6.119 +													 const char *value, 
   6.120 +													 bool key_quotes, 
   6.121 +													 bool value_quotes)
   6.122 +{
   6.123 +	if (cur_plugin != -1)
   6.124 +	{
   6.125 +		PluginSettings *plugin = (PluginSettings *)m_strtab->GetMemTable()->GetAddress(cur_plugin);
   6.126 +		if (!in_options)
   6.127 +		{
   6.128 +			if (strcmp(key, "pause") == 0)
   6.129 +			{
   6.130 +				if (strcasecmp(value, "yes") == 0)
   6.131 +				{
   6.132 +					plugin->pause_val = true;
   6.133 +				} else {
   6.134 +					plugin->pause_val = false;
   6.135 +				}
   6.136 +			} else if (strcmp(key, "lifetime") == 0) {
   6.137 +				if (strcasecmp(value, "private") == 0)
   6.138 +				{
   6.139 +					plugin->type_val = PluginType_Private;
   6.140 +				} else if (strcasecmp(value, "mapsync") == 0) {
   6.141 +					plugin->type_val = PluginType_MapUpdated;
   6.142 +				} else if (strcasecmp(value, "maponly") == 0) {
   6.143 +					plugin->type_val = PluginType_MapOnly;
   6.144 +				} else if (strcasecmp(value, "global") == 0) {
   6.145 +					plugin->type_val = PluginType_Global;
   6.146 +				} else {
   6.147 +					return MakeError("Unknown value for key \"lifetime\": \"%s\"", value);
   6.148 +				}
   6.149 +			} else {
   6.150 +				return MakeError("Unknown property key: \"%s\"", key);
   6.151 +			}
   6.152 +		} else {
   6.153 +			/* Cache every option, valid or not */
   6.154 +			int keyidx = m_strtab->AddString(key);
   6.155 +			int validx = m_strtab->AddString(value);
   6.156 +			PluginOpts *table;
   6.157 +			BaseMemTable *memtab = m_strtab->GetMemTable();
   6.158 +			if (plugin->opts_num + 1 > plugin->opts_size)
   6.159 +			{
   6.160 +				unsigned int oldsize = plugin->opts_size;
   6.161 +				if (oldsize == 0)
   6.162 +				{
   6.163 +					//right now we don't have many
   6.164 +					plugin->opts_size = 2;
   6.165 +				} else {
   6.166 +					plugin->opts_size *= 2;
   6.167 +				}
   6.168 +				int newidx = memtab->CreateMem(plugin->opts_size * sizeof(PluginOpts), (void **)&table);
   6.169 +				if (plugin->optarray != -1)
   6.170 +				{
   6.171 +					void *oldtable = memtab->GetAddress(plugin->optarray);
   6.172 +					memcpy(table, oldtable, oldsize * sizeof(PluginOpts));
   6.173 +				}
   6.174 +				plugin->optarray = newidx;
   6.175 +			} else {
   6.176 +				table = (PluginOpts *)memtab->GetAddress(plugin->optarray);
   6.177 +			}
   6.178 +			PluginOpts *opt = &table[plugin->opts_num++];
   6.179 +			opt->key = keyidx;
   6.180 +			opt->val = validx;
   6.181 +		}
   6.182 +	} else if (in_plugins) {
   6.183 +		return MakeError("Unknown property key: \"%s\"", key);
   6.184 +	} else {
   6.185 +		/* Ignore anything we don't know about! */
   6.186 +	}
   6.187 +
   6.188 +	return SMCParse_Continue;
   6.189 +}
   6.190 +
   6.191 +SMCParseResult CPluginInfoDatabase::ReadSMC_LeavingSection()
   6.192 +{
   6.193 +	if (in_plugins)
   6.194 +	{
   6.195 +		if (cur_plugin == -1)
   6.196 +		{
   6.197 +			if (in_options)
   6.198 +			{
   6.199 +				in_options = false;
   6.200 +			} else {
   6.201 +				/* If the plugin is ending, add it to the table */
   6.202 +				BaseMemTable *memtab = m_strtab->GetMemTable();
   6.203 +				int *table;
   6.204 +				if (m_infodb_count + 1 > m_infodb_size)
   6.205 +				{
   6.206 +					unsigned int oldsize = m_infodb_size;
   6.207 +					if (!m_infodb_size)
   6.208 +					{
   6.209 +						m_infodb_size = 8;
   6.210 +					} else {
   6.211 +						m_infodb_size *= 2;
   6.212 +					}
   6.213 +					int newidx = memtab->CreateMem(m_infodb_size, (void **)&table);
   6.214 +					if (m_infodb != -1)
   6.215 +					{
   6.216 +						void *oldtable = (int *)memtab->GetAddress(m_infodb);
   6.217 +						memcpy(table, oldtable, oldsize * sizeof(int));
   6.218 +					}
   6.219 +					m_infodb = newidx;
   6.220 +				} else {
   6.221 +					table = (int *)memtab->GetAddress(m_infodb);
   6.222 +				}
   6.223 +				/* Assign to table and scrap the current plugin */
   6.224 +				table[m_infodb_count++] = cur_plugin;
   6.225 +				cur_plugin = -1;
   6.226 +			}
   6.227 +		} else {
   6.228 +			in_plugins = false;
   6.229 +		}
   6.230 +	}
   6.231 +
   6.232 +	return SMCParse_Continue;
   6.233 +}
   6.234 +
   6.235 +SMCParseResult CPluginInfoDatabase::ReadSMC_NewSection(const char *name, bool opt_quotes)
   6.236 +{
   6.237 +	if (!in_plugins)
   6.238 +	{
   6.239 +		/* If we're not in the main Plugins section, and we don't get it for the name, error out */
   6.240 +		if (strcmp(name, "Plugins") != 0)
   6.241 +		{
   6.242 +			return MakeError("Unknown root section: \"%s\"", name);
   6.243 +		} else {
   6.244 +			/* Otherwise set our states */
   6.245 +			in_plugins = true;
   6.246 +			cur_plugin = -1;
   6.247 +			in_options = false;
   6.248 +		}
   6.249 +	} else {
   6.250 +		if (cur_plugin == -1)
   6.251 +		{
   6.252 +			/* If we get a plugin node and we don't have a current plugin, create a new one */
   6.253 +			PluginSettings *plugin;
   6.254 +			cur_plugin = m_strtab->GetMemTable()->CreateMem(sizeof(PluginSettings), (void **)&plugin);
   6.255 +			plugin->Init();
   6.256 +			plugin->name = m_strtab->AddString(name);
   6.257 +			in_options = false;
   6.258 +		} else {
   6.259 +			if (!in_options && strcmp(name, "Options") == 0)
   6.260 +			{
   6.261 +				in_options = true;
   6.262 +			} else {
   6.263 +				return MakeError("Unknown plugin sub-section: \"%s\"", name);
   6.264 +			}
   6.265 +		}
   6.266 +	}
   6.267 +
   6.268 +	return SMCParse_Continue;
   6.269 +}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/core/systems/PluginInfoDatabase.h	Sun Dec 10 09:19:59 2006 +0000
     7.3 @@ -0,0 +1,74 @@
     7.4 +#ifndef _INCLUDE_SOURCEMOD_CORE_SYSTEM_PLUGININFODATABASE_H_
     7.5 +#define _INCLUDE_SOURCEMOD_CORE_SYSTEM_PLUGININFODATABASE_H_
     7.6 +
     7.7 +/**
     7.8 + * This file parses plugin_settings.cfg and stores the information in cached memory.
     7.9 + * It provides simplistic abstraction to retrieving the info.
    7.10 + * :TODO: currently untested
    7.11 + */
    7.12 +
    7.13 +#include "sm_memtable.h"
    7.14 +#include "ITextParsers.h"
    7.15 +#include "IPluginSys.h"
    7.16 +#include "sm_globals.h"
    7.17 +
    7.18 +struct PluginOpts
    7.19 +{
    7.20 +	int key;
    7.21 +	int val;
    7.22 +};
    7.23 +
    7.24 +struct PluginSettings
    7.25 +{
    7.26 +	void Init();
    7.27 +	int name;
    7.28 +	bool pause_val;
    7.29 +	PluginType type_val;
    7.30 +	int optarray;
    7.31 +	size_t opts_num;
    7.32 +	size_t opts_size;
    7.33 +};
    7.34 +
    7.35 +class CPluginInfoDatabase : public ITextListener_SMC
    7.36 +{
    7.37 +public:
    7.38 +	CPluginInfoDatabase();
    7.39 +	~CPluginInfoDatabase();
    7.40 +public: //ITextListener_SMC
    7.41 +	void ReadSMC_ParseStart();
    7.42 +	SMCParseResult ReadSMC_NewSection(const char *name, bool opt_quotes);
    7.43 +	SMCParseResult ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes);
    7.44 +	SMCParseResult ReadSMC_LeavingSection();
    7.45 +public:
    7.46 +	/**
    7.47 +	 * Returns the number of plugin settings available.
    7.48 +	 */
    7.49 +	unsigned int GetSettingsNum();
    7.50 +
    7.51 +	/** 
    7.52 +	 * Given an index, returns the plugin settings block if the filename matches.
    7.53 +	 * Otherwise, returns NULL.
    7.54 +	 */
    7.55 +	PluginSettings *GetSettingsIfMatch(unsigned int index, const char *filename);
    7.56 +
    7.57 +	/** 
    7.58 +	 *  Given a plugin settings struct and an index,
    7.59 +	 * returns the given JIT key/value option pair at that index.
    7.60 +	 * If the input is invalid, key and val will be set to NULL.
    7.61 +	 */
    7.62 +	void GetOptionsForPlugin(PluginSettings *settings, unsigned int opt_num, const char **key, const char **val);
    7.63 +private:
    7.64 +	SMCParseResult MakeError(const char *fmt, ...);
    7.65 +private:
    7.66 +	BaseStringTable *m_strtab;
    7.67 +	int m_errmsg;
    7.68 +	bool in_plugins;
    7.69 +	bool in_options;
    7.70 +	unsigned int m_infodb;
    7.71 +	size_t m_infodb_count;
    7.72 +	size_t m_infodb_size;
    7.73 +	int cur_plugin;
    7.74 +};
    7.75 +
    7.76 +
    7.77 +#endif //_INCLUDE_SOURCEMOD_CORE_SYSTEM_PLUGININFODATABASE_H_
     8.1 --- a/core/systems/PluginSys.cpp	Sat Dec 09 03:18:48 2006 +0000
     8.2 +++ b/core/systems/PluginSys.cpp	Sun Dec 10 09:19:59 2006 +0000
     8.3 @@ -2,6 +2,7 @@
     8.4  #include "PluginSys.h"
     8.5  #include "LibrarySys.h"
     8.6  #include "sourcemm_api.h"
     8.7 +#include "CTextParsers.h"
     8.8  
     8.9  CPluginManager g_PluginMngr;
    8.10  
    8.11 @@ -288,9 +289,19 @@
    8.12   * PLUGIN MANAGER *
    8.13   ******************/
    8.14  
    8.15 -void CPluginManager::RefreshOrLoadPlugins(const char *basedir)
    8.16 +void CPluginManager::RefreshOrLoadPlugins(const char *config, const char *basedir)
    8.17  {
    8.18 -	IDirectory *dir = g_LibSys.OpenDirectory(basedir);
    8.19 +	/* First read in the database of plugin settings */
    8.20 +	SMCParseError err;
    8.21 +	unsigned int line, col;
    8.22 +	if ((err=g_TextParse.ParseFile_SMC(config, &m_PluginInfo, &line, &col)) != SMCParse_Okay)
    8.23 +	{
    8.24 +		/* :TODO: log the error, don't bail out though */
    8.25 +	}
    8.26 +
    8.27 +
    8.28 +	//:TODO: move this to a separate recursive function and do stuff
    8.29 +	/*IDirectory *dir = g_LibSys.OpenDirectory(basedir);
    8.30  	while (dir->MoreFiles())
    8.31  	{
    8.32  		if (dir->IsEntryDirectory() && (strcmp(dir->GetEntryName(), "disabled") != 0))
    8.33 @@ -300,7 +311,7 @@
    8.34  			RefreshOrLoadPlugins(basedir);
    8.35  		}
    8.36  	}
    8.37 -	g_LibSys.CloseDirectory(dir);
    8.38 +	g_LibSys.CloseDirectory(dir);*/
    8.39  }
    8.40  
    8.41  IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType type, char error[], size_t err_max)
    8.42 @@ -446,6 +457,215 @@
    8.43  	}
    8.44  }
    8.45  
    8.46 +bool CPluginManager::TestAliasMatch(const char *alias, const char *localpath)
    8.47 +{
    8.48 +	/* As an optimization, we do not call strlen, but compute the length in the first pass */
    8.49 +	size_t alias_len = 0;
    8.50 +	size_t local_len = 0;
    8.51 +
    8.52 +	const char *ptr = alias;
    8.53 +	unsigned int alias_explicit_paths = 0;
    8.54 +	unsigned int alias_path_end = 0;
    8.55 +	while (*ptr != '\0')
    8.56 +	{
    8.57 +		if (*ptr == '\\' || *ptr == '/')
    8.58 +		{
    8.59 +			alias_explicit_paths++;
    8.60 +			alias_path_end = alias_len;
    8.61 +		}
    8.62 +		alias_len++;
    8.63 +		ptr++;
    8.64 +	}
    8.65 +
    8.66 +	if (alias_path_end == alias_len - 1)
    8.67 +	{
    8.68 +		/* Trailing slash is totally invalid here */
    8.69 +		return false;
    8.70 +	}
    8.71 +
    8.72 +	ptr = localpath;
    8.73 +	unsigned int local_explicit_paths = 0;
    8.74 +	unsigned int local_path_end = 0;
    8.75 +	while (*ptr != '\0')
    8.76 +	{
    8.77 +		if (*ptr == '\\' || *ptr == '/')
    8.78 +		{
    8.79 +			local_explicit_paths++;
    8.80 +			local_path_end = local_len;
    8.81 +		}
    8.82 +		local_len++;
    8.83 +		ptr++;
    8.84 +	}
    8.85 +
    8.86 +	/* If the alias has more explicit paths than the real path,
    8.87 +	 * no match will be possible.
    8.88 +	 */
    8.89 +	if (alias_explicit_paths > local_explicit_paths)
    8.90 +	{
    8.91 +		return false;
    8.92 +	}
    8.93 +
    8.94 +	if (alias_explicit_paths)
    8.95 +	{
    8.96 +		/* We need to find if the paths match now.  For example, these should all match:
    8.97 +		 * csdm     csdm
    8.98 +		 * csdm     optional/csdm
    8.99 +		 * csdm/ban optional/crab/csdm/ban
   8.100 +		*/
   8.101 +		const char *aliasptr = alias;
   8.102 +		const char *localptr = localpath;
   8.103 +		bool match = true;
   8.104 +		do
   8.105 +		{
   8.106 +			if (*aliasptr != *localptr)
   8.107 +			{
   8.108 +				/* We have to knock one path off */
   8.109 +				local_explicit_paths--;
   8.110 +				if (alias_explicit_paths > local_explicit_paths)
   8.111 +				{
   8.112 +					/* Skip out if we're gonna have an impossible match */
   8.113 +					return false;
   8.114 +				}
   8.115 +				/* Eat up localptr tokens until we get a result */
   8.116 +				while (((localptr - localpath) < (int)local_path_end)
   8.117 +					&& *localptr != '/'
   8.118 +					&& *localptr != '\\')
   8.119 +				{
   8.120 +					localptr++;
   8.121 +				}
   8.122 +				/* Check if we hit the end of our searchable area.
   8.123 +				 * This probably isn't possible because of the path 
   8.124 +				 * count check, but it's a good idea anyway.
   8.125 +				 */
   8.126 +				if ((localptr - localpath) >= (int)local_path_end)
   8.127 +				{
   8.128 +					return false;
   8.129 +				} else {
   8.130 +					/* Consume the slash token */
   8.131 +					localptr++;
   8.132 +				}
   8.133 +				/* Reset the alias pointer so we can continue consuming */
   8.134 +				aliasptr = alias;
   8.135 +				match = false;
   8.136 +				continue;
   8.137 +			}
   8.138 +			/* Note:
   8.139 +			 * This is safe because if localptr terminates early, aliasptr will too
   8.140 +			 */
   8.141 +			do
   8.142 +			{
   8.143 +				/* We should never reach the end of the string because of this check. */
   8.144 +				bool aliasend = (aliasptr - alias) > (int)alias_path_end;
   8.145 +				bool localend = (localptr - localpath) > (int)local_path_end;
   8.146 +				if (aliasend || localend)
   8.147 +				{
   8.148 +					if (aliasend && localend)
   8.149 +					{
   8.150 +						/* we matched, and we can break out now */
   8.151 +						match = true;
   8.152 +						break;
   8.153 +					}
   8.154 +					/* Otherwise, we've hit the end somehow and rest won't match up.  Break out. */
   8.155 +					match = false;
   8.156 +					break;
   8.157 +				}
   8.158 +
   8.159 +				/* If we got here, it's safe to compare the next two tokens */
   8.160 +				if (*localptr != *aliasptr)
   8.161 +				{
   8.162 +					match = false;
   8.163 +					break;
   8.164 +				}
   8.165 +				localptr++;
   8.166 +				aliasptr++;
   8.167 +			} while (true);
   8.168 +		} while (!match);
   8.169 +	}
   8.170 +
   8.171 +	/* If we got here, it's time to compare filenames */
   8.172 +	const char *aliasptr = alias;
   8.173 +	const char *localptr = localpath;
   8.174 +
   8.175 +	if (alias_explicit_paths)
   8.176 +	{
   8.177 +		aliasptr = &alias[alias_path_end + 1];
   8.178 +	}
   8.179 +
   8.180 +	if (local_explicit_paths)
   8.181 +	{
   8.182 +		localptr = &localpath[local_path_end + 1];
   8.183 +	}
   8.184 +
   8.185 +	while (true)
   8.186 +	{
   8.187 +		if (*aliasptr == '*')
   8.188 +		{
   8.189 +			/* First, see if this is the last character */
   8.190 +			if (aliasptr - alias == alias_len - 1)
   8.191 +			{
   8.192 +				/* If so, there's no need to match anything else */
   8.193 +				return true;
   8.194 +			}
   8.195 +			/* Otherwise, we need to search for an appropriate matching sequence in local.
   8.196 +			 * Note that we only need to search up to the next asterisk.
   8.197 +			 */
   8.198 +			aliasptr++;
   8.199 +			bool match = true;
   8.200 +			const char *local_orig = localptr;
   8.201 +			do
   8.202 +			{
   8.203 +				match = true;
   8.204 +				while (*aliasptr != '\0' && *aliasptr != '*')
   8.205 +				{
   8.206 +					/* Since aliasptr is never '\0', localptr hitting the end will fail */
   8.207 +					if (*aliasptr != *localptr)
   8.208 +					{
   8.209 +						match = false;
   8.210 +						break;
   8.211 +					}
   8.212 +					aliasptr++;
   8.213 +					localptr++;
   8.214 +				}
   8.215 +				if (!match)
   8.216 +				{
   8.217 +					/* If we didn't get a match, we need to advance the search stream.
   8.218 +					 * This will let us skip tokens while still searching for another match.
   8.219 +					 */
   8.220 +					localptr = ++local_orig;
   8.221 +					/* Make sure we don't go out of bounds */
   8.222 +					if (*localptr == '\0')
   8.223 +					{
   8.224 +						break;
   8.225 +					}
   8.226 +				}
   8.227 +			} while (!match);
   8.228 +
   8.229 +			if (!match)
   8.230 +			{
   8.231 +				return false;
   8.232 +			} else {
   8.233 +				/* If we got a match, move on to the next token */
   8.234 +				continue;
   8.235 +			}
   8.236 +		} else if (*aliasptr == '\0') {
   8.237 +			if (*localptr == '\0'
   8.238 +				||
   8.239 +				strcmp(localptr, ".smx") == 0)
   8.240 +			{
   8.241 +				return true;
   8.242 +			} else {
   8.243 +				return false;
   8.244 +			}
   8.245 +		} else if (*aliasptr != *localptr) {
   8.246 +			return false;
   8.247 +		}
   8.248 +		aliasptr++;
   8.249 +		localptr++;
   8.250 +	}
   8.251 +
   8.252 +	return true;
   8.253 +}
   8.254 +
   8.255  CPluginManager::~CPluginManager()
   8.256  {
   8.257  	//:TODO: we need a good way to free what we're holding
     9.1 --- a/core/systems/PluginSys.h	Sat Dec 09 03:18:48 2006 +0000
     9.2 +++ b/core/systems/PluginSys.h	Sun Dec 10 09:19:59 2006 +0000
     9.3 @@ -6,6 +6,7 @@
     9.4  #include <sh_stack.h>
     9.5  #include "sm_globals.h"
     9.6  #include "CFunction.h"
     9.7 +#include "PluginInfoDatabase.h"
     9.8  
     9.9  using namespace SourceHook;
    9.10  
    9.11 @@ -60,6 +61,13 @@
    9.12  	CFunction **m_pub_funcs;
    9.13  };
    9.14  
    9.15 +struct PluginDBInfo
    9.16 +{
    9.17 +	bool pause;
    9.18 +	PluginType lifetime;
    9.19 +
    9.20 +};
    9.21 +
    9.22  class CPluginManager : public IPluginManager
    9.23  {
    9.24  	friend class CPlugin;
    9.25 @@ -67,6 +75,7 @@
    9.26  	CPluginManager();
    9.27  	~CPluginManager();
    9.28  public:
    9.29 +	/* Implements iterator class */
    9.30  	class CPluginIterator : public IPluginIterator
    9.31  	{
    9.32  	public:
    9.33 @@ -83,7 +92,7 @@
    9.34  		List<IPlugin *>::iterator current;
    9.35  	};
    9.36  	friend class CPluginManager::CPluginIterator;
    9.37 -public:
    9.38 +public: //IPluginManager
    9.39  	virtual IPlugin *LoadPlugin(const char *path, 
    9.40  								bool debug,
    9.41  								PluginType type,
    9.42 @@ -96,7 +105,21 @@
    9.43  	virtual void AddPluginsListener(IPluginsListener *listener);
    9.44  	virtual void RemovePluginsListener(IPluginsListener *listener);
    9.45  public:
    9.46 -	virtual void RefreshOrLoadPlugins(const char *basedir);
    9.47 +	/**
    9.48 +	 * Refreshes and loads plugins, usually used on mapchange
    9.49 +	 */
    9.50 +	virtual void RefreshOrLoadPlugins(const char *config, const char *basedir);
    9.51 +
    9.52 +	/**
    9.53 +	 * Tests a plugin file mask against a local folder.
    9.54 +	 * The alias is searched backwards from localdir - i.e., given this input:
    9.55 +	 *   csdm/ban        csdm/ban
    9.56 +	 *   ban             csdm/ban
    9.57 +	 *   csdm/ban        optional/csdm/ban
    9.58 +	 * All of these will return true for an alias match.  
    9.59 +	 * Wildcards are allowed in the filename.
    9.60 +	 */
    9.61 +	virtual bool TestAliasMatch(const char *alias, const char *localdir);
    9.62  protected:
    9.63  	void ReleaseIterator(CPluginIterator *iter);
    9.64  	CFunction *GetFunctionFromPool(funcid_t f, CPlugin *plugin);
    9.65 @@ -106,6 +129,7 @@
    9.66  	List<IPlugin *> m_plugins;
    9.67  	CStack<CPluginManager::CPluginIterator *> m_iters;
    9.68  	CStack<CFunction *> m_funcpool;
    9.69 +	CPluginInfoDatabase m_PluginInfo;
    9.70  };
    9.71  
    9.72  extern CPluginManager g_PluginMngr;