core/CoreConfig.cpp
author Scott Ehlert <ds@alliedmods.net>
Wed Aug 15 06:19:30 2007 +0000 (2007-08-15)
changeset 1330 ab94316bb52b
parent 1231 17badaf66ce4
child 1406 f5c07ec3c052
permissions -rw-r--r--
Updated license headers on virtually all files with extremely minor changes in the name of some sort of strange consistency.
All plugin and include file headers also have been changed to say about GPL3 instead of GPL2.

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