core/Database.cpp
author David Anderson <dvander@alliedmods.net>
Wed Jun 06 06:04:16 2007 +0000 (2007-06-06)
changeset 883 f4eff9faf362
parent 869 caa5587e708a
child 1096 8e11b2ebdc22
permissions -rw-r--r--
fixed inheritance not being used in the base menu style when removing clients from the watch list
     1 /**
     2  * vim: set ts=4 :
     3  * ===============================================================
     4  * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     5  * ===============================================================
     6  *
     7  * This file is not open source and may not be copied without explicit
     8  * written permission of AlliedModders LLC.  This file may not be redistributed 
     9  * in whole or significant part.
    10  * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
    11  *
    12  * Version: $Id$
    13  */
    14 
    15 #include "Database.h"
    16 #include "HandleSys.h"
    17 #include "ShareSys.h"
    18 #include "sourcemod.h"
    19 #include "sm_stringutil.h"
    20 #include "TextParsers.h"
    21 #include "Logger.h"
    22 #include "ExtensionSys.h"
    23 #include <stdlib.h>
    24 
    25 #define DBPARSE_LEVEL_NONE		0
    26 #define DBPARSE_LEVEL_MAIN		1
    27 #define DBPARSE_LEVEL_DATABASE	2
    28 
    29 DBManager g_DBMan;
    30 
    31 DBManager::DBManager() 
    32 : m_StrTab(512), m_ParseLevel(0), m_ParseState(0), m_pDefault(NULL)
    33 {
    34 }
    35 
    36 void DBManager::OnSourceModAllInitialized()
    37 {
    38 	HandleAccess sec;
    39 
    40 	g_HandleSys.InitAccessDefaults(NULL, &sec);
    41 	sec.access[HandleAccess_Delete] |= HANDLE_RESTRICT_IDENTITY;
    42 	sec.access[HandleAccess_Clone] |= HANDLE_RESTRICT_IDENTITY;
    43 	
    44 	m_DriverType = g_HandleSys.CreateType("IDriver", this, 0, NULL, &sec, g_pCoreIdent, NULL);
    45 	m_DatabaseType = g_HandleSys.CreateType("IDatabase", this, 0, NULL, NULL, g_pCoreIdent, NULL);
    46 
    47 	g_ShareSys.AddInterface(NULL, this);
    48 
    49 	g_SourceMod.BuildPath(Path_SM, m_Filename, sizeof(m_Filename), "configs/databases.cfg");
    50 }
    51 
    52 void DBManager::OnSourceModLevelChange(const char *mapName)
    53 {
    54 	SMCParseError err;
    55 	unsigned int line = 0;
    56 	if ((err = g_TextParser.ParseFile_SMC(m_Filename, this, &line, NULL)) != SMCParse_Okay)
    57 	{
    58 		g_Logger.LogError("[SM] Detected parse error(s) in file \"%s\"", m_Filename);
    59 		if (err != SMCParse_Custom)
    60 		{
    61 			const char *txt = g_TextParser.GetSMCErrorString(err);
    62 			g_Logger.LogError("[SM] Line %d: %s", line, txt);
    63 		}
    64 	}
    65 }
    66 
    67 void DBManager::OnSourceModShutdown()
    68 {
    69 	g_HandleSys.RemoveType(m_DatabaseType, g_pCoreIdent);
    70 	g_HandleSys.RemoveType(m_DriverType, g_pCoreIdent);
    71 }
    72 
    73 unsigned int DBManager::GetInterfaceVersion()
    74 {
    75 	return SMINTERFACE_DBI_VERSION;
    76 }
    77 
    78 const char *DBManager::GetInterfaceName()
    79 {
    80 	return SMINTERFACE_DBI_NAME;
    81 }
    82 
    83 void DBManager::OnHandleDestroy(HandleType_t type, void *object)
    84 {
    85 	if (type == m_DriverType)
    86 	{
    87 		/* Ignore */
    88 		return;
    89 	}
    90 
    91 	if (g_HandleSys.TypeCheck(type, m_DatabaseType))
    92 	{
    93 		IDatabase *pdb = (IDatabase *)object;
    94 		pdb->Close();
    95 	}
    96 }
    97 
    98 void DBManager::ReadSMC_ParseStart()
    99 {
   100 	m_confs.clear();
   101 	m_ParseLevel = 0;
   102 	m_ParseState = DBPARSE_LEVEL_NONE;
   103 	m_StrTab.Reset();
   104 	m_DefDriver.clear();
   105 }
   106 
   107 ConfDbInfo s_CurInfo;
   108 SMCParseResult DBManager::ReadSMC_NewSection(const char *name, bool opt_quotes)
   109 {
   110 	if (m_ParseLevel)
   111 	{
   112 		m_ParseLevel++;
   113 		return SMCParse_Continue;
   114 	}
   115 
   116 	if (m_ParseState == DBPARSE_LEVEL_NONE)
   117 	{
   118 		if (strcmp(name, "Databases") == 0)
   119 		{
   120 			m_ParseState = DBPARSE_LEVEL_MAIN;
   121 		} else {
   122 			m_ParseLevel++;
   123 		}
   124 	} else if (m_ParseState == DBPARSE_LEVEL_MAIN) {
   125 		s_CurInfo = ConfDbInfo();
   126 		s_CurInfo.name = m_StrTab.AddString(name);
   127 		m_ParseState = DBPARSE_LEVEL_DATABASE;
   128 	} else if (m_ParseState == DBPARSE_LEVEL_DATABASE) {
   129 		m_ParseLevel++;
   130 	}
   131 
   132 	return SMCParse_Continue;
   133 }
   134 
   135 SMCParseResult DBManager::ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes)
   136 {
   137 	if (m_ParseLevel)
   138 	{
   139 		return SMCParse_Continue;
   140 	}
   141 
   142 	if (m_ParseState == DBPARSE_LEVEL_MAIN)
   143 	{
   144 		if (strcmp(key, "driver_default") == 0)
   145 		{
   146 			m_DefDriver.assign(value);
   147 		}
   148 	} else if (m_ParseState == DBPARSE_LEVEL_DATABASE) {
   149 		if (strcmp(key, "driver") == 0)
   150 		{
   151 			if (strcmp(value, "default") != 0)
   152 			{
   153 				s_CurInfo.driver = m_StrTab.AddString(value);
   154 			}
   155 		} else if (strcmp(key, "database") == 0) {
   156 			s_CurInfo.database = m_StrTab.AddString(value);
   157 		} else if (strcmp(key, "host") == 0) {
   158 			s_CurInfo.host = m_StrTab.AddString(value);
   159 		} else if (strcmp(key, "user") == 0) {
   160 			s_CurInfo.user = m_StrTab.AddString(value);
   161 		} else if (strcmp(key, "pass") == 0) {
   162 			s_CurInfo.pass = m_StrTab.AddString(value);
   163 		} else if (strcmp(key, "timeout") == 0) {
   164 			s_CurInfo.info.maxTimeout = atoi(value);
   165 		} else if (strcmp(key, "port") == 0) {
   166 			s_CurInfo.info.port = atoi(value);
   167 		}
   168 	}
   169 
   170 	return SMCParse_Continue;
   171 }
   172 
   173 #define ASSIGN_VAR(var) \
   174 	if (s_CurInfo.var == -1) { \
   175 		s_CurInfo.info.var = ""; \
   176 	} else { \
   177 		s_CurInfo.info.var = m_StrTab.GetString(s_CurInfo.var); \
   178 	}
   179 
   180 SMCParseResult DBManager::ReadSMC_LeavingSection()
   181 {
   182 	if (m_ParseLevel)
   183 	{
   184 		m_ParseLevel--;
   185 		return SMCParse_Continue;
   186 	}
   187 
   188 	if (m_ParseState == DBPARSE_LEVEL_DATABASE)
   189 	{
   190 		/* Set all of the info members to either a blank string
   191 		 * or the string pointer from the string table.
   192 		 */
   193 		ASSIGN_VAR(driver);
   194 		ASSIGN_VAR(database);
   195 		ASSIGN_VAR(host);
   196 		ASSIGN_VAR(user);
   197 		ASSIGN_VAR(pass);
   198 		
   199 		/* Save it.. */
   200 		m_confs.push_back(s_CurInfo);
   201 
   202 		/* Go up one level */
   203 		m_ParseState = DBPARSE_LEVEL_MAIN;
   204 	} else if (m_ParseState == DBPARSE_LEVEL_MAIN) {
   205 		m_ParseState = DBPARSE_LEVEL_NONE;
   206 		return SMCParse_Halt;
   207 	}
   208 
   209 	return SMCParse_Continue;
   210 }
   211 #undef ASSIGN_VAR
   212 
   213 void DBManager::ReadSMC_ParseEnd(bool halted, bool failed)
   214 {
   215 }
   216 
   217 bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool persistent, char *error, size_t maxlength)
   218 {
   219 	ConfDbInfo *pInfo = GetDatabaseConf(name);
   220 
   221 	if (!pInfo)
   222 	{
   223 		if (pdr)
   224 		{
   225 			*pdr = NULL;
   226 		}
   227 		*pdb = NULL;
   228 		UTIL_Format(error, maxlength, "Configuration \"%s\" not found", name);
   229 		return false;
   230 	}
   231 
   232 	const char *dname = pInfo->info.driver;
   233 	if (!pInfo->realDriver)
   234 	{
   235 		/* Try to assign a real driver pointer */
   236 		if (pInfo->info.driver[0] == '\0')
   237 		{
   238 			if (!m_pDefault && m_DefDriver.size() > 0)
   239 			{
   240 				m_pDefault = FindOrLoadDriver(m_DefDriver.c_str());
   241 			}
   242 			dname = m_DefDriver.size() ? m_DefDriver.c_str() : "default";
   243 			pInfo->realDriver = m_pDefault;
   244 		} else {
   245 			pInfo->realDriver = FindOrLoadDriver(pInfo->info.driver);
   246 		}
   247 	}
   248 
   249 	if (pInfo->realDriver)
   250 	{
   251 		if (pdr)
   252 		{
   253 			*pdr = pInfo->realDriver;
   254 		}
   255 		*pdb = pInfo->realDriver->Connect(&pInfo->info, persistent, error, maxlength);
   256 		return (*pdb != NULL);
   257 	}
   258 
   259 	if (pdr)
   260 	{
   261 		*pdr = NULL;
   262 	}
   263 	*pdb = NULL;
   264 
   265 	UTIL_Format(error, maxlength, "Driver \"%s\" not found", dname);
   266 
   267 	return false;
   268 }
   269 
   270 void DBManager::AddDriver(IDBDriver *pDriver)
   271 {
   272 	 m_drivers.push_back(pDriver);
   273 }
   274 
   275 void DBManager::RemoveDriver(IDBDriver *pDriver)
   276 {
   277 	for (size_t i=0; i<m_drivers.size(); i++)
   278 	{
   279 		if (m_drivers[i] == pDriver)
   280 		{
   281 			m_drivers.erase(m_drivers.iterAt(i));
   282 			return;
   283 		}
   284 	}
   285 
   286 	/* Make sure NOTHING references this! */
   287 	List<ConfDbInfo>::iterator iter;
   288 	for (iter=m_confs.begin(); iter!=m_confs.end(); iter++)
   289 	{
   290 		ConfDbInfo &db = (*iter);
   291 		if (db.realDriver == pDriver)
   292 		{
   293 			db.realDriver = NULL;
   294 		}
   295 	}
   296 }
   297 
   298 IDBDriver *DBManager::GetDefaultDriver()
   299 {
   300 	if (!m_pDefault && m_DefDriver.size() > 0)
   301 	{
   302 		m_pDefault = FindOrLoadDriver(m_DefDriver.c_str());
   303 	}
   304 
   305 	return m_pDefault;
   306 }
   307 
   308 Handle_t DBManager::CreateHandle(DBHandleType dtype, void *ptr, IdentityToken_t *pToken)
   309 {
   310 	HandleType_t type = 0;
   311 
   312 	if (dtype == DBHandle_Driver)
   313 	{
   314 		type = m_DriverType;
   315 	} else if (dtype == DBHandle_Database) {
   316 		type = m_DatabaseType;
   317 	} else {
   318 		return BAD_HANDLE;
   319 	}
   320 
   321 	return g_HandleSys.CreateHandle(type, ptr, pToken, g_pCoreIdent, NULL);
   322 }
   323 
   324 HandleError DBManager::ReadHandle(Handle_t hndl, DBHandleType dtype, void **ptr)
   325 {
   326 	HandleType_t type = 0;
   327 
   328 	if (dtype == DBHandle_Driver)
   329 	{
   330 		type = m_DriverType;
   331 	} else if (dtype == DBHandle_Database) {
   332 		type = m_DatabaseType;
   333 	} else {
   334 		return HandleError_Type;
   335 	}
   336 
   337 	HandleSecurity sec(NULL, g_pCoreIdent);
   338 
   339 	return g_HandleSys.ReadHandle(hndl, type, &sec, ptr);
   340 }
   341 
   342 HandleError DBManager::ReleaseHandle(Handle_t hndl, DBHandleType type, IdentityToken_t *token)
   343 {
   344 	HandleSecurity sec(token, g_pCoreIdent);
   345 	return g_HandleSys.FreeHandle(hndl, &sec);
   346 }
   347 
   348 unsigned int DBManager::GetDriverCount()
   349 {
   350 	return (unsigned int)m_drivers.size();
   351 }
   352 
   353 IDBDriver *DBManager::GetDriver(unsigned int index)
   354 {
   355 	if (index >= m_drivers.size())
   356 	{
   357 		return NULL;
   358 	}
   359 
   360 	return m_drivers[index];
   361 }
   362 
   363 const DatabaseInfo *DBManager::FindDatabaseConf(const char *name)
   364 {
   365 	ConfDbInfo *info = GetDatabaseConf(name);
   366 	if (!info)
   367 	{
   368 		return NULL;
   369 	}
   370 
   371 	return &info->info;
   372 }
   373 
   374 ConfDbInfo *DBManager::GetDatabaseConf(const char *name)
   375 {
   376 	List<ConfDbInfo>::iterator iter;
   377 
   378 	for (iter=m_confs.begin(); iter!=m_confs.end(); iter++)
   379 	{
   380 		ConfDbInfo &conf = (*iter);
   381 		if (strcmp(m_StrTab.GetString(conf.name), name) == 0)
   382 		{
   383 			return &conf;
   384 		}
   385 	}
   386 
   387 	return NULL;
   388 }
   389 
   390 IDBDriver *DBManager::FindOrLoadDriver(const char *name)
   391 {
   392 	size_t last_size = m_drivers.size();
   393 	for (size_t i=0; i<last_size; i++)
   394 	{
   395 		if (strcmp(m_drivers[i]->GetIdentifier(), name) == 0)
   396 		{
   397 			return m_drivers[i];
   398 		}
   399 	}
   400 
   401 	char filename[PLATFORM_MAX_PATH];
   402 	UTIL_Format(filename, sizeof(filename), "dbi.%s.ext", name);
   403 
   404 	IExtension *pExt = g_Extensions.LoadAutoExtension(filename);
   405 	if (!pExt || !pExt->IsLoaded() || m_drivers.size() <= last_size)
   406 	{
   407 		return NULL;
   408 	}
   409 
   410 	/* last_size is now gauranteed to be a valid index.
   411 	 * The identifier must match the name.
   412 	 */
   413 	if (strcmp(m_drivers[last_size]->GetIdentifier(), name) == 0)
   414 	{
   415 		return m_drivers[last_size];
   416 	}
   417 
   418 	return NULL;
   419 }