core/CoreConfig.cpp
author David Anderson <dvander@alliedmods.net>
Tue Jul 03 20:46:17 2007 +0000 (2007-07-03)
changeset 1036 2a073d5b3454
parent 1021 49db3567848c
child 1192 94ee3f012044
permissions -rw-r--r--
added amb505
     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 "CoreConfig.h"
    16 #include "sourcemod.h"
    17 #include "sourcemm_api.h"
    18 #include "sm_srvcmds.h"
    19 #include "sm_version.h"
    20 #include "sm_stringutil.h"
    21 #include "LibrarySys.h"
    22 #include "TextParsers.h"
    23 #include "Logger.h"
    24 #include "PluginSys.h"
    25 #include "ForwardSys.h"
    26 
    27 #ifdef PLATFORM_WINDOWS
    28 ConVar sm_corecfgfile("sm_corecfgfile", "addons\\sourcemod\\configs\\core.cfg", 0, "SourceMod core configuration file");
    29 #elif defined PLATFORM_LINUX
    30 ConVar sm_corecfgfile("sm_corecfgfile", "addons/sourcemod/configs/core.cfg", 0, "SourceMod core configuration file");
    31 #endif
    32 
    33 IForward *g_pOnServerCfg = NULL;
    34 IForward *g_pOnConfigsExecuted = NULL;
    35 CoreConfig g_CoreConfig;
    36 bool g_bConfigsExecd = false;
    37 
    38 void CoreConfig::OnSourceModAllInitialized()
    39 {
    40 	g_RootMenu.AddRootConsoleCommand("config", "Set core configuration options", this);
    41 	g_pOnServerCfg = g_Forwards.CreateForward("OnServerCfg", ET_Ignore, 0, NULL);
    42 	g_pOnConfigsExecuted = g_Forwards.CreateForward("OnConfigsExecuted", ET_Ignore, 0, NULL);
    43 }
    44 
    45 void CoreConfig::OnSourceModShutdown()
    46 {
    47 	g_RootMenu.RemoveRootConsoleCommand("config", this);
    48 	g_Forwards.ReleaseForward(g_pOnServerCfg);
    49 	g_Forwards.ReleaseForward(g_pOnConfigsExecuted);
    50 }
    51 
    52 void CoreConfig::OnSourceModLevelChange(const char *mapName)
    53 {
    54 	g_bConfigsExecd = false;
    55 }
    56 
    57 void CoreConfig::OnRootConsoleCommand(const char *command, unsigned int argcount)
    58 {
    59 	if (argcount >= 4)
    60 	{
    61 		const char *option = engine->Cmd_Argv(2);
    62 		const char *value = engine->Cmd_Argv(3);
    63 
    64 		char error[255];
    65 
    66 		ConfigResult res = SetConfigOption(option, value, ConfigSource_Console, error, sizeof(error));
    67 
    68 		if (res == ConfigResult_Reject)
    69 		{
    70 			g_RootMenu.ConsolePrint("[SM] Could not set config option \"%s\" to \"%s\" (%s)", option, value, error);
    71 		} else if (res == ConfigResult_Ignore) {
    72 			g_RootMenu.ConsolePrint("[SM] No such config option \"%s\" exists.", option);
    73 		} else {
    74 			g_RootMenu.ConsolePrint("Config option \"%s\" successfully set to \"%s.\"", option, value);
    75 		}
    76 
    77 		return;
    78 	}
    79 
    80 	g_RootMenu.ConsolePrint("[SM] Usage: sm config <option> <value>");
    81 }
    82 
    83 void CoreConfig::Initialize()
    84 {
    85 	SMCParseError err;
    86 	char filePath[PLATFORM_MAX_PATH];
    87 
    88 	/* Try to get command line value of core config convar */
    89 	const char *corecfg = icvar->GetCommandLineValue("sm_corecfgfile");
    90 
    91 	/* If sm_corecfgfile not specified on command line, use default value */
    92 	if (!corecfg)
    93 	{
    94 		corecfg = sm_corecfgfile.GetDefault();
    95 	}
    96 
    97 	/* Format path to config file */
    98 	g_LibSys.PathFormat(filePath, sizeof(filePath), "%s/%s", g_SourceMod.GetGamePath(), corecfg);
    99 
   100 	/* Parse config file */
   101 	if ((err=g_TextParser.ParseFile_SMC(filePath, this, NULL, NULL)) != SMCParse_Okay)
   102 	{
   103  		/* :TODO: This won't actually log or print anything :( - So fix that somehow */
   104 		const char *error = g_TextParser.GetSMCErrorString(err);
   105 		g_Logger.LogFatal("[SM] Error encountered parsing core config file: %s", error ? error : "");
   106 	}
   107 }
   108 
   109 SMCParseResult CoreConfig::ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes)
   110 {
   111 	char error[255];
   112 	ConfigResult err = SetConfigOption(key, value, ConfigSource_File, error, sizeof(error));
   113 
   114 	if (err == ConfigResult_Reject)
   115 	{
   116 		/* This is a fatal error */
   117 		g_Logger.LogFatal("Config error (key: %s) (value: %s) %s", key, value, error);
   118 	}
   119 
   120 	return SMCParse_Continue;
   121 }
   122 
   123 ConfigResult CoreConfig::SetConfigOption(const char *option, const char *value, ConfigSource source, char *error, size_t maxlength)
   124 {
   125 	ConfigResult result;
   126 
   127 	/* Notify! */
   128 	SMGlobalClass *pBase = SMGlobalClass::head;
   129 	while (pBase)
   130 	{
   131 		if ((result = pBase->OnSourceModConfigChanged(option, value, source, error, maxlength)) != ConfigResult_Ignore)
   132 		{
   133 			return result;
   134 		}
   135 		pBase = pBase->m_pGlobalClassNext;
   136 	}
   137 
   138 	return ConfigResult_Ignore;
   139 }
   140 
   141 bool SM_AreConfigsExecuted()
   142 {
   143 	return g_bConfigsExecd;
   144 }
   145 
   146 inline bool IsPathSepChar(char c)
   147 {
   148 #if defined PLATFORM_WINDOWS
   149 	return (c == '\\' || c == '/');
   150 #elif defined PLATFORM_LINUX
   151 	return (c == '/');
   152 #endif
   153 }
   154 
   155 bool SM_ExecuteConfig(CPlugin *pl, AutoConfig *cfg, bool can_create)
   156 {
   157 	bool will_create = false;
   158 	
   159 	/* See if we should be creating */
   160 	if (can_create && cfg->create)
   161 	{
   162 		will_create = true;
   163 		
   164 		/* If the folder does not exist, attempt to create it.  
   165 		 * We're awfully nice.
   166 		 */
   167 		const char *folder = cfg->folder.c_str();
   168 		char path[PLATFORM_MAX_PATH];
   169 		char build[PLATFORM_MAX_PATH];
   170 
   171 		g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "cfg/%s", folder);
   172 
   173 		if (!g_LibSys.IsPathDirectory(path))
   174 		{
   175 			char *cur_ptr = path;
   176 			size_t len;
   177 			
   178 			g_LibSys.PathFormat(path, sizeof(path), "%s", folder);
   179 			len = g_SourceMod.BuildPath(Path_Game, build, sizeof(build), "cfg");
   180 
   181 			do
   182 			{
   183 				/* Find next suitable path */
   184 				char *next_ptr = cur_ptr;
   185 				while (*next_ptr != '\0')
   186 				{
   187 					if (IsPathSepChar(*next_ptr))
   188 					{
   189 						*next_ptr = '\0';
   190 						next_ptr++;
   191 						break;
   192 					}
   193 					next_ptr++;
   194 				}
   195 				if (*next_ptr == '\0')
   196 				{
   197 					next_ptr = NULL;
   198 				}
   199 				len += g_LibSys.PathFormat(&build[len], 
   200 					sizeof(build)-len,
   201 					"/%s",
   202 					cur_ptr);
   203 				if (!g_LibSys.CreateDirectory(build))
   204 				{
   205 					break;
   206 				}
   207 				cur_ptr = next_ptr;
   208 			} while (cur_ptr);
   209 		}
   210 	}
   211 
   212 	/* Check if the file exists. */
   213 	char file[PLATFORM_MAX_PATH];
   214 	char local[PLATFORM_MAX_PATH];
   215 
   216 	if (cfg->folder.size())
   217 	{
   218 		g_LibSys.PathFormat(local, 
   219 			sizeof(local), 
   220 			"%s/%s.cfg",
   221 			cfg->folder.c_str(),
   222 			cfg->autocfg.c_str());
   223 	} else {
   224 		g_LibSys.PathFormat(local,
   225 			sizeof(local),
   226 			"%s.cfg",
   227 			cfg->autocfg.c_str());
   228 	}
   229 	
   230 	g_SourceMod.BuildPath(Path_Game, file, sizeof(file), "cfg/%s", local);
   231 
   232 	bool file_exists = g_LibSys.IsPathFile(file);
   233 	if (!file_exists && will_create)
   234 	{
   235 		List<const ConVar *> *convars = NULL;
   236 		if (pl->GetProperty("ConVarList", (void **)&convars, false) && convars)
   237 		{
   238 			/* Attempt to create it */
   239 			FILE *fp = fopen(file, "wt");
   240 			if (fp)
   241 			{
   242 				fprintf(fp, "// This file was auto-generated by SourceMod (v%s)\n", SVN_FULL_VERSION);
   243 				fprintf(fp, "// ConVars for plugin \"%s\"\n", pl->GetFilename());
   244 				fprintf(fp, "\n\n");
   245 
   246 				List<const ConVar *>::iterator iter;
   247 				float x;
   248 				for (iter = convars->begin(); iter != convars->end(); iter++)
   249 				{
   250 					const ConVar *cvar = (*iter);
   251 
   252 					if ((cvar->GetFlags() & FCVAR_DONTRECORD) == FCVAR_DONTRECORD)
   253 					{
   254 						continue;
   255 					}
   256 
   257 					char descr[255];
   258 					char *dptr = descr;
   259 
   260 					/* Print comments until there is no more */
   261 					strncopy(descr, cvar->GetHelpText(), sizeof(descr));
   262 					while (*dptr != '\0')
   263 					{
   264 						/* Find the next line */
   265 						char *next_ptr = dptr;
   266 						while (*next_ptr != '\0')
   267 						{
   268 							if (*next_ptr == '\n')
   269 							{
   270 								*next_ptr = '\0';
   271 								next_ptr++;
   272 								break;
   273 							}
   274 							next_ptr++;
   275 						}
   276 						fprintf(fp, "// %s\n", dptr);
   277 						dptr = next_ptr;
   278 					}
   279 
   280 					fprintf(fp, "// -\n");
   281 					fprintf(fp, "// Default: \"%s\"\n", cvar->GetDefault());
   282 					if (cvar->GetMin(x))
   283 					{
   284 						fprintf(fp, "// Minimum: \"%02f\"\n", x);
   285 					}
   286 					if (cvar->GetMax(x))
   287 					{
   288 						fprintf(fp, "// Maximum: \"%02f\"\n", x);
   289 					}
   290 					fprintf(fp, "%s \"%s\"\n", cvar->GetName(), cvar->GetDefault());
   291 					fprintf(fp, "\n");
   292 				}
   293 				fprintf(fp, "\n");
   294 
   295 				file_exists = true;
   296 				can_create = false;
   297 				fclose(fp);
   298 			}
   299 		}
   300 	}
   301 
   302 	if (file_exists)
   303 	{
   304 		char cmd[255];
   305 		UTIL_Format(cmd, sizeof(cmd), "exec %s\n", local);
   306 		engine->ServerCommand(cmd);
   307 	}
   308 
   309 	return can_create;
   310 }
   311 
   312 void SM_DoSingleExecFwds(IPluginContext *ctx)
   313 {
   314 	IPluginFunction *pf;
   315 
   316 	if ((pf = ctx->GetFunctionByName("OnServerCfg")) != NULL)
   317 	{
   318 		pf->Execute(NULL);
   319 	}
   320 
   321 	if ((pf = ctx->GetFunctionByName("OnConfigsExecuted")) != NULL)
   322 	{
   323 		pf->Execute(NULL);
   324 	}
   325 }
   326 
   327 void SM_ConfigsExecuted_Plugin(unsigned int serial)
   328 {
   329 	IPluginIterator *iter = g_PluginSys.GetPluginIterator();
   330 	while (iter->MorePlugins())
   331 	{
   332 		CPlugin *plugin = (CPlugin *)(iter->GetPlugin());
   333 		if (plugin->GetSerial() == serial)
   334 		{
   335 			SM_DoSingleExecFwds(plugin->GetBaseContext());
   336 			break;
   337 		}
   338 		iter->NextPlugin();
   339 	}
   340 	iter->Release();
   341 }
   342 
   343 void SM_ExecuteForPlugin(IPluginContext *ctx)
   344 {
   345 	CPlugin *plugin = (CPlugin *)g_PluginSys.GetPluginByCtx(ctx->GetContext());
   346 
   347 	unsigned int num = plugin->GetConfigCount();
   348 	if (!num)
   349 	{
   350 		SM_DoSingleExecFwds(ctx);
   351 	} else {
   352 		bool can_create = true;
   353 		for (unsigned int i=0; i<num; i++)
   354 		{
   355 			can_create = SM_ExecuteConfig(plugin, plugin->GetConfig(i), can_create);
   356 		}
   357 		char cmd[255];
   358 		UTIL_Format(cmd, sizeof(cmd), "sm internal 2 %d\n", plugin->GetSerial());
   359 		engine->ServerCommand(cmd);
   360 	}
   361 }
   362 
   363 void SM_ExecuteAllConfigs()
   364 {
   365 	if (g_bConfigsExecd)
   366 	{
   367 		return;
   368 	}
   369 
   370 	engine->ServerCommand("exec sourcemod/sourcemod.cfg\n");
   371 
   372 	IPluginIterator *iter = g_PluginSys.GetPluginIterator();
   373 	while (iter->MorePlugins())
   374 	{
   375 		CPlugin *plugin = (CPlugin *)(iter->GetPlugin());
   376 		unsigned int num = plugin->GetConfigCount();
   377 		bool can_create = true;
   378 		for (unsigned int i=0; i<num; i++)
   379 		{
   380 			can_create = SM_ExecuteConfig(plugin, plugin->GetConfig(i), can_create);
   381 		}
   382 		iter->NextPlugin();
   383 	}
   384 	iter->Release();
   385 
   386 	engine->ServerCommand("sm internal 1\n");
   387 }
   388 
   389 void SM_ConfigsExecuted_Global()
   390 {
   391 	if (g_bConfigsExecd)
   392 	{
   393 		return;
   394 	}
   395 
   396 	g_bConfigsExecd = true;
   397 
   398 	g_pOnServerCfg->Execute(NULL);
   399 	g_pOnConfigsExecuted->Execute(NULL);
   400 }