core/sm_srvcmds.cpp
author David Anderson <dvander@alliedmods.net>
Tue Dec 04 15:58:07 2007 +0000 (2007-12-04)
changeset 1764 e4f24e9789fd
parent 1687 47cc645edce6
child 1770 9c545310f947
permissions -rw-r--r--
- removed ancient bcompat shim for translations/core.cfg file
- fixed msvc8 whining about BfReadString
     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 "sm_srvcmds.h"
    33 #include "sm_version.h"
    34 #include "sm_stringutil.h"
    35 #include "HandleSys.h"
    36 #include "CoreConfig.h"
    37 
    38 RootConsoleMenu g_RootMenu;
    39 
    40 ConVar sourcemod_version("sourcemod_version", SVN_FULL_VERSION, FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY, "SourceMod Version");
    41 
    42 RootConsoleMenu::RootConsoleMenu()
    43 {
    44 	m_pCommands = sm_trie_create();
    45 	m_CfgExecDone = false;
    46 }
    47 
    48 RootConsoleMenu::~RootConsoleMenu()
    49 {
    50 	sm_trie_destroy(m_pCommands);
    51 
    52 	List<ConsoleEntry *>::iterator iter;
    53 	for (iter=m_Menu.begin(); iter!=m_Menu.end(); iter++)
    54 	{
    55 		delete (*iter);
    56 	}
    57 	m_Menu.clear();
    58 }
    59 
    60 #if defined ORANGEBOX_BUILD
    61 	extern void _IntExt_OnHostnameChanged(IConVar *var, const char *pOldValue, float flOldValue);
    62 #else
    63 	extern void _IntExt_OnHostnameChanged(ConVar *pConVar, char const *oldValue);
    64 #endif
    65 
    66 void RootConsoleMenu::OnSourceModStartup(bool late)
    67 {
    68 #if defined ORANGEBOX_BUILD
    69 	g_pCVar = icvar;
    70 #endif
    71 	CONVAR_REGISTER(this);
    72 	AddRootConsoleCommand("version", "Display version information", this);
    73 	AddRootConsoleCommand("credits", "Display credits listing", this);
    74 
    75 	ConVar *pHost = icvar->FindVar("hostname");
    76 	pHost->InstallChangeCallback(_IntExt_OnHostnameChanged);
    77 }
    78 
    79 void RootConsoleMenu::OnSourceModShutdown()
    80 {
    81 	RemoveRootConsoleCommand("credits", this);
    82 	RemoveRootConsoleCommand("version", this);
    83 }
    84 
    85 bool RootConsoleMenu::RegisterConCommandBase(ConCommandBase *pCommand)
    86 {
    87 	META_REGCVAR(pCommand);
    88 
    89 	/* Override values of convars created by SourceMod convar manager if specified on command line */
    90 	const char *cmdLineValue = icvar->GetCommandLineValue(pCommand->GetName());
    91 	if (cmdLineValue && !pCommand->IsCommand())
    92 	{
    93 		static_cast<ConVar *>(pCommand)->SetValue(cmdLineValue);
    94 	}
    95 
    96 	return true;
    97 }
    98 
    99 void RootConsoleMenu::ConsolePrint(const char *fmt, ...)
   100 {
   101 	char buffer[512];
   102 
   103 	va_list ap;
   104 	va_start(ap, fmt);
   105 	size_t len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
   106 	va_end(ap);
   107 
   108 	if (len >= sizeof(buffer) - 1)
   109 	{
   110 		buffer[510] = '\n';
   111 		buffer[511] = '\0';
   112 	} else {
   113 		buffer[len++] = '\n';
   114 		buffer[len] = '\0';
   115 	}
   116 	
   117 	META_CONPRINT(buffer);
   118 }
   119 
   120 bool RootConsoleMenu::AddRootConsoleCommand(const char *cmd, const char *text, IRootConsoleCommand *pHandler)
   121 {
   122 	if (sm_trie_retrieve(m_pCommands, cmd, NULL))
   123 	{
   124 		return false;
   125 	}
   126 
   127 	sm_trie_insert(m_pCommands, cmd, pHandler);
   128 
   129 	/* Sort this into the menu */
   130 	List<ConsoleEntry *>::iterator iter = m_Menu.begin();
   131 	ConsoleEntry *pEntry;
   132 	bool inserted = false;
   133 	while (iter != m_Menu.end())
   134 	{
   135 		pEntry = (*iter);
   136 		if (strcmp(cmd, pEntry->command.c_str()) < 0)
   137 		{
   138 			ConsoleEntry *pNew = new ConsoleEntry;
   139 			pNew->command.assign(cmd);
   140 			pNew->description.assign(text);
   141 			m_Menu.insert(iter, pNew);
   142 			inserted = true;
   143 			break;
   144 		}
   145 		iter++;
   146 	}
   147 
   148 	if (!inserted)
   149 	{
   150 		ConsoleEntry *pNew = new ConsoleEntry;
   151 		pNew->command.assign(cmd);
   152 		pNew->description.assign(text);
   153 		m_Menu.push_back(pNew);
   154 	}
   155 
   156 	return true;
   157 }
   158 
   159 bool RootConsoleMenu::RemoveRootConsoleCommand(const char *cmd, IRootConsoleCommand *pHandler)
   160 {
   161 	/* Sanity tests */
   162 	IRootConsoleCommand *object;
   163 	if (sm_trie_retrieve(m_pCommands, cmd, (void **)&object))
   164 	{
   165 		if (object != pHandler)
   166 		{
   167 			return false;
   168 		}
   169 	} else {
   170 		return false;
   171 	}
   172 
   173 	sm_trie_delete(m_pCommands, cmd);
   174 
   175 	List<ConsoleEntry *>::iterator iter;
   176 	ConsoleEntry *pEntry;
   177 	for (iter=m_Menu.begin(); iter!=m_Menu.end(); iter++)
   178 	{
   179 		pEntry = (*iter);
   180 		if (pEntry->command.compare(cmd) == 0)
   181 		{
   182 			delete pEntry;
   183 			m_Menu.erase(iter);
   184 			break;
   185 		}
   186 	}
   187 
   188 	return true;
   189 }
   190 
   191 void RootConsoleMenu::DrawGenericOption(const char *cmd, const char *text)
   192 {
   193 	char buffer[255];
   194 	size_t len, cmdlen = strlen(cmd);
   195 
   196 	len = UTIL_Format(buffer, sizeof(buffer), "    %s", cmd);
   197 	if (cmdlen < 16)
   198 	{
   199 		size_t num = 16 - cmdlen;
   200 		for (size_t i = 0; i < num; i++)
   201 		{
   202 			buffer[len++] = ' ';
   203 		}
   204 		len += snprintf(&buffer[len], sizeof(buffer) - len, " - %s", text);
   205 		ConsolePrint("%s", buffer);
   206 	}
   207 }
   208 
   209 extern void _IntExt_EnableYams();
   210 
   211 void RootConsoleMenu::GotRootCmd(const CCommand &cmd)
   212 {
   213 	unsigned int argnum = cmd.ArgC();
   214 
   215 	if (argnum >= 2)
   216 	{
   217 		const char *cmdname = cmd.Arg(1);
   218 		if (strcmp(cmdname, "text") == 0)
   219 		{
   220 			_IntExt_EnableYams();
   221 			return;
   222 		}
   223 		else if (strcmp(cmdname, "internal") == 0)
   224 		{
   225 			if (argnum >= 3)
   226 			{
   227 				const char *arg = cmd.Arg(2);
   228 				if (strcmp(arg, "1") == 0)
   229 				{
   230 					SM_ConfigsExecuted_Global();
   231 				}
   232 				else if (strcmp(arg, "2") == 0)
   233 				{
   234 					if (argnum >= 4)
   235 					{
   236 						SM_ConfigsExecuted_Plugin(atoi(cmd.Arg(3)));
   237 					}
   238 				}
   239 			}
   240 			return;
   241 		}
   242 
   243 		IRootConsoleCommand *pHandler;
   244 		if (sm_trie_retrieve(m_pCommands, cmdname, (void **)&pHandler))
   245 		{
   246 			pHandler->OnRootConsoleCommand(cmdname, cmd);
   247 			return;
   248 		}
   249 	}
   250 
   251 	ConsolePrint("SourceMod Menu:");
   252 	ConsolePrint("Usage: sm <command> [arguments]");
   253 
   254 	List<ConsoleEntry *>::iterator iter;
   255 	ConsoleEntry *pEntry;
   256 	for (iter=m_Menu.begin(); iter!=m_Menu.end(); iter++)
   257 	{
   258 		pEntry = (*iter);
   259 		DrawGenericOption(pEntry->command.c_str(), pEntry->description.c_str());
   260 	}
   261 }
   262 
   263 void RootConsoleMenu::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
   264 {
   265 	if (strcmp(cmdname, "credits") == 0)
   266 	{
   267 		ConsolePrint(" SourceMod was developed by AlliedModders, LLC.");
   268 		ConsolePrint(" Development would not have been possible without the following people:");
   269 		ConsolePrint("  David \"BAILOPAN\" Anderson, lead developer");
   270 		ConsolePrint("  Borja \"faluco\" Ferrer, Core developer");
   271 		ConsolePrint("  Scott \"Damaged Soul\" Ehlert, Core developer");
   272 		ConsolePrint("  Pavol \"PM OnoTo\" Marko, SourceHook developer");
   273 		ConsolePrint(" Special thanks to Viper of GameConnect");
   274 		ConsolePrint(" Special thanks to Mani of Mani-Admin-Plugin");
   275 		ConsolePrint(" http://www.sourcemod.net/");
   276 	} else if (strcmp(cmdname, "version") == 0) {
   277 		ConsolePrint(" SourceMod Version Information:");
   278 		ConsolePrint("    SourceMod Version: %s", SVN_FULL_VERSION);
   279 		ConsolePrint("    JIT Version: %s, %s", g_pVM->GetVMName(), g_pVM->GetVersionString());
   280 		ConsolePrint("    JIT Settings: %s", g_pVM->GetCPUOptimizations());
   281 		ConsolePrint("    http://www.sourcemod.net/");
   282 	}
   283 }
   284 
   285 CON_COMMAND(sm, "SourceMod Menu")
   286 {
   287 #if !defined ORANGEBOX_BUILD
   288 	CCommand args;
   289 #endif
   290 	g_RootMenu.GotRootCmd(args);
   291 }
   292 
   293 FILE *g_pHndlLog = NULL;
   294 
   295 void write_handles_to_log(const char *fmt, ...)
   296 {
   297 	va_list ap;
   298 	
   299 	va_start(ap, fmt);
   300 	vfprintf(g_pHndlLog, fmt, ap);
   301 	fprintf(g_pHndlLog, "\n");
   302 	va_end(ap);
   303 }
   304 
   305 void write_handles_to_game(const char *fmt, ...)
   306 {
   307 	size_t len;
   308 	va_list ap;
   309 	char buffer[1024];
   310 	
   311 	va_start(ap, fmt);
   312 	len = UTIL_FormatArgs(buffer, sizeof(buffer)-2, fmt, ap);
   313 	va_end(ap);
   314 
   315 	buffer[len] = '\n';
   316 	buffer[len+1] = '\0';
   317 
   318 	engine->LogPrint(buffer);
   319 }
   320 
   321 CON_COMMAND(sm_dump_handles, "Dumps Handle usage to a file for finding Handle leaks")
   322 {
   323 #if !defined ORANGEBOX_BUILD
   324 	CCommand args;
   325 #endif
   326 	if (args.ArgC() < 2)
   327 	{
   328 		g_RootMenu.ConsolePrint("Usage: sm_dump_handles <file> or <log> for game logs");
   329 		return;
   330 	}
   331 
   332 	if (strcmp(args.Arg(1), "log") != 0)
   333 	{
   334 		const char *arg = args.Arg(1);
   335 		FILE *fp = fopen(arg, "wt");
   336 		if (!fp)
   337 		{
   338 			g_RootMenu.ConsolePrint("Could not find file \"%s\"", arg);
   339 			return;
   340 		}
   341 
   342 		g_pHndlLog = fp;
   343 		g_HandleSys.Dump(write_handles_to_log);
   344 		g_pHndlLog = NULL;
   345 
   346 		fclose(fp);
   347 	}
   348 	else
   349 	{
   350 		g_HandleSys.Dump(write_handles_to_game);
   351 	}
   352 }