dvander@370: /**
dvander@2728: * vim: set ts=4 sw=4 :
ds@1330: * =============================================================================
dvander@1231: * SourceMod
dvander@2728: * Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
ds@1330: * =============================================================================
dvander@370: *
ds@1330: * This program is free software; you can redistribute it and/or modify it under
ds@1330: * the terms of the GNU General Public License, version 3.0, as published by the
ds@1330: * Free Software Foundation.
dvander@1231: *
ds@1330: * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1330: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1330: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
ds@1330: * details.
dvander@1231: *
ds@1330: * You should have received a copy of the GNU General Public License along with
ds@1330: * this program. If not, see .
dvander@1231: *
ds@1330: * As a special exception, AlliedModders LLC gives you permission to link the
ds@1330: * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1330: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1330: * by the Valve Corporation. You must obey the GNU General Public License in
ds@1330: * all respects for all other code used. Additionally, AlliedModders LLC grants
ds@1330: * this exception to all derivative works. AlliedModders LLC defines further
ds@1330: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1330: * or .
dvander@370: *
dvander@370: * Version: $Id$
dvander@370: */
dvander@370:
faluco@216: #include "sm_srvcmds.h"
dvander@2784: #include
faluco@274: #include "sm_stringutil.h"
dvander@900: #include "HandleSys.h"
dvander@978: #include "CoreConfig.h"
dvander@1770: #include "ConVarManager.h"
dvander@1883: #include "ShareSys.h"
faluco@216:
dvander@308: RootConsoleMenu g_RootMenu;
faluco@216:
dvander@2784: ConVar sourcemod_version("sourcemod_version", SM_FULL_VERSION, FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY, "SourceMod Version");
dvander@524:
dvander@308: RootConsoleMenu::RootConsoleMenu()
faluco@216: {
dvander@308: m_pCommands = sm_trie_create();
dvander@978: m_CfgExecDone = false;
faluco@216: }
faluco@216:
dvander@308: RootConsoleMenu::~RootConsoleMenu()
dvander@308: {
dvander@308: sm_trie_destroy(m_pCommands);
dvander@308:
dvander@308: List::iterator iter;
dvander@308: for (iter=m_Menu.begin(); iter!=m_Menu.end(); iter++)
dvander@308: {
dvander@308: delete (*iter);
dvander@308: }
dvander@308: m_Menu.clear();
dvander@308: }
dvander@308:
dvander@308: void RootConsoleMenu::OnSourceModStartup(bool late)
dvander@308: {
ds@2400: #if SOURCE_ENGINE >= SE_ORANGEBOX
dvander@1542: g_pCVar = icvar;
faluco@1541: #endif
faluco@1541: CONVAR_REGISTER(this);
dvander@308: AddRootConsoleCommand("version", "Display version information", this);
dvander@308: AddRootConsoleCommand("credits", "Display credits listing", this);
dvander@1770: }
ds@627:
dvander@1770: void RootConsoleMenu::OnSourceModAllInitialized()
dvander@1770: {
dvander@1883: g_ShareSys.AddInterface(NULL, this);
dvander@308: }
dvander@308:
dvander@308: void RootConsoleMenu::OnSourceModShutdown()
dvander@308: {
dvander@308: RemoveRootConsoleCommand("credits", this);
dvander@308: RemoveRootConsoleCommand("version", this);
dvander@308: }
dvander@308:
dvander@308: bool RootConsoleMenu::RegisterConCommandBase(ConCommandBase *pCommand)
faluco@216: {
faluco@216: META_REGCVAR(pCommand);
faluco@216:
ds@657: /* Override values of convars created by SourceMod convar manager if specified on command line */
ds@657: const char *cmdLineValue = icvar->GetCommandLineValue(pCommand->GetName());
ds@657: if (cmdLineValue && !pCommand->IsCommand())
ds@657: {
ds@657: static_cast(pCommand)->SetValue(cmdLineValue);
ds@657: }
ds@657:
faluco@216: return true;
faluco@216: }
faluco@216:
dvander@308: void RootConsoleMenu::ConsolePrint(const char *fmt, ...)
dvander@308: {
dvander@308: char buffer[512];
dvander@308:
dvander@308: va_list ap;
dvander@308: va_start(ap, fmt);
dvander@308: size_t len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
dvander@308: va_end(ap);
dvander@308:
dvander@324: if (len >= sizeof(buffer) - 1)
dvander@308: {
dvander@308: buffer[510] = '\n';
dvander@308: buffer[511] = '\0';
dvander@308: } else {
dvander@308: buffer[len++] = '\n';
dvander@308: buffer[len] = '\0';
dvander@308: }
dvander@308:
dvander@308: META_CONPRINT(buffer);
dvander@308: }
dvander@308:
dvander@308: bool RootConsoleMenu::AddRootConsoleCommand(const char *cmd, const char *text, IRootConsoleCommand *pHandler)
faluco@216: {
dvander@2728: return _AddRootConsoleCommand(cmd, text, pHandler, false);
dvander@2728: }
dvander@2728:
dvander@2728: bool RootConsoleMenu::AddRootConsoleCommand2(const char *cmd, const char *text, IRootConsoleCommand *pHandler)
dvander@2728: {
dvander@2728: return _AddRootConsoleCommand(cmd, text, pHandler, true);
dvander@2728: }
dvander@2728:
dvander@2728: bool RootConsoleMenu::_AddRootConsoleCommand(const char *cmd,
dvander@2728: const char *text,
dvander@2728: IRootConsoleCommand *pHandler,
dvander@2728: bool version2)
dvander@2728: {
dvander@308: if (sm_trie_retrieve(m_pCommands, cmd, NULL))
dvander@308: {
dvander@308: return false;
dvander@308: }
dvander@308:
dvander@308: /* Sort this into the menu */
dvander@308: List::iterator iter = m_Menu.begin();
dvander@308: ConsoleEntry *pEntry;
dvander@308: bool inserted = false;
dvander@308: while (iter != m_Menu.end())
dvander@308: {
dvander@308: pEntry = (*iter);
dvander@308: if (strcmp(cmd, pEntry->command.c_str()) < 0)
dvander@308: {
dvander@308: ConsoleEntry *pNew = new ConsoleEntry;
dvander@308: pNew->command.assign(cmd);
dvander@308: pNew->description.assign(text);
dvander@2728: pNew->version2 = version2;
dvander@2728: pNew->cmd = pHandler;
dvander@2728: sm_trie_insert(m_pCommands, cmd, pNew);
dvander@308: m_Menu.insert(iter, pNew);
dvander@308: inserted = true;
dvander@308: break;
dvander@308: }
dvander@308: iter++;
dvander@308: }
dvander@308:
dvander@308: if (!inserted)
dvander@308: {
dvander@308: ConsoleEntry *pNew = new ConsoleEntry;
dvander@308: pNew->command.assign(cmd);
dvander@308: pNew->description.assign(text);
dvander@2728: pNew->version2 = version2;
dvander@2728: pNew->cmd = pHandler;
dvander@2728: sm_trie_insert(m_pCommands, cmd, pNew);
dvander@308: m_Menu.push_back(pNew);
dvander@308: }
dvander@308:
dvander@308: return true;
dvander@308: }
dvander@308:
dvander@308: bool RootConsoleMenu::RemoveRootConsoleCommand(const char *cmd, IRootConsoleCommand *pHandler)
dvander@308: {
dvander@308: sm_trie_delete(m_pCommands, cmd);
dvander@308:
dvander@308: List::iterator iter;
dvander@308: ConsoleEntry *pEntry;
dvander@308: for (iter=m_Menu.begin(); iter!=m_Menu.end(); iter++)
dvander@308: {
dvander@308: pEntry = (*iter);
dvander@308: if (pEntry->command.compare(cmd) == 0)
dvander@308: {
dvander@308: delete pEntry;
dvander@308: m_Menu.erase(iter);
dvander@308: break;
dvander@308: }
dvander@308: }
dvander@308:
dvander@308: return true;
dvander@308: }
dvander@308:
dvander@309: void RootConsoleMenu::DrawGenericOption(const char *cmd, const char *text)
dvander@309: {
dvander@309: char buffer[255];
dvander@309: size_t len, cmdlen = strlen(cmd);
dvander@309:
faluco@651: len = UTIL_Format(buffer, sizeof(buffer), " %s", cmd);
dvander@309: if (cmdlen < 16)
dvander@309: {
dvander@309: size_t num = 16 - cmdlen;
dvander@309: for (size_t i = 0; i < num; i++)
dvander@309: {
dvander@309: buffer[len++] = ' ';
dvander@309: }
dvander@309: len += snprintf(&buffer[len], sizeof(buffer) - len, " - %s", text);
dvander@309: ConsolePrint("%s", buffer);
dvander@309: }
dvander@309: }
dvander@309:
dvander@1883: const char *RootConsoleMenu::GetInterfaceName()
dvander@1883: {
dvander@1883: return SMINTERFACE_ROOTCONSOLE_NAME;
dvander@1883: }
dvander@1883:
dvander@1883: unsigned int RootConsoleMenu::GetInterfaceVersion()
dvander@1883: {
dvander@1883: return SMINTERFACE_ROOTCONSOLE_VERSION;
dvander@1883: }
dvander@1883:
dvander@2728: #if SOURCE_ENGINE==SE_EPISODEONE || SOURCE_ENGINE==SE_DARKMESSIAH
dvander@2728: class CCommandArgs : public ICommandArgs
dvander@2728: {
dvander@2728: public:
dvander@2728: CCommandArgs(const CCommand& _cmd)
dvander@2728: {
dvander@2728: }
dvander@2728: const char *Arg(int n) const
dvander@2728: {
dvander@2728: return engine->Cmd_Argv(n);
dvander@2728: }
dvander@2728: int ArgC() const
dvander@2728: {
dvander@2728: return engine->Cmd_Argc();
dvander@2728: }
dvander@2728: const char *ArgS() const
dvander@2728: {
dvander@2728: return engine->Cmd_Args();
dvander@2728: }
dvander@2728: };
dvander@2728: #else
dvander@2728: class CCommandArgs : public ICommandArgs
dvander@2728: {
dvander@2728: const CCommand *cmd;
dvander@2728: public:
dvander@2728: CCommandArgs(const CCommand& _cmd) : cmd(&_cmd)
dvander@2728: {
dvander@2728: }
dvander@2728: const char *Arg(int n) const
dvander@2728: {
dvander@2728: return cmd->Arg(n);
dvander@2728: }
dvander@2728: int ArgC() const
dvander@2728: {
dvander@2728: return cmd->ArgC();
dvander@2728: }
dvander@2728: const char *ArgS() const
dvander@2728: {
dvander@2728: return cmd->ArgS();
dvander@2728: }
dvander@2728: };
dvander@2728: #endif
dvander@2728:
faluco@1541: void RootConsoleMenu::GotRootCmd(const CCommand &cmd)
dvander@308: {
faluco@1541: unsigned int argnum = cmd.ArgC();
faluco@216:
faluco@216: if (argnum >= 2)
faluco@216: {
faluco@1541: const char *cmdname = cmd.Arg(1);
dvander@1902: if (strcmp(cmdname, "internal") == 0)
dvander@1630: {
dvander@978: if (argnum >= 3)
dvander@978: {
faluco@1541: const char *arg = cmd.Arg(2);
dvander@978: if (strcmp(arg, "1") == 0)
dvander@978: {
dvander@978: SM_ConfigsExecuted_Global();
dvander@1630: }
dvander@1630: else if (strcmp(arg, "2") == 0)
dvander@1630: {
dvander@978: if (argnum >= 4)
dvander@978: {
faluco@1541: SM_ConfigsExecuted_Plugin(atoi(cmd.Arg(3)));
dvander@978: }
dvander@978: }
dvander@978: }
dvander@978: return;
dvander@614: }
dvander@978:
dvander@2728: CCommandArgs ocmd(cmd);
dvander@2728:
dvander@2728: ConsoleEntry *entry;
dvander@2728: if (sm_trie_retrieve(m_pCommands, cmdname, (void **)&entry))
faluco@216: {
dvander@2728: if (entry->version2)
dvander@2728: {
dvander@2728: entry->cmd->OnRootConsoleCommand2(cmdname, &ocmd);
dvander@2728: }
dvander@2728: else
dvander@2728: {
dvander@2728: entry->cmd->OnRootConsoleCommand(cmdname, cmd);
dvander@2728: }
faluco@270: return;
faluco@216: }
faluco@216: }
dvander@308:
dvander@308: ConsolePrint("SourceMod Menu:");
dvander@308: ConsolePrint("Usage: sm [arguments]");
dvander@308:
dvander@308: List::iterator iter;
dvander@308: ConsoleEntry *pEntry;
dvander@308: for (iter=m_Menu.begin(); iter!=m_Menu.end(); iter++)
dvander@308: {
dvander@308: pEntry = (*iter);
dvander@309: DrawGenericOption(pEntry->command.c_str(), pEntry->description.c_str());
dvander@308: }
dvander@308: }
dvander@308:
faluco@1541: void RootConsoleMenu::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
dvander@308: {
faluco@1541: if (strcmp(cmdname, "credits") == 0)
dvander@308: {
dvander@308: ConsolePrint(" SourceMod was developed by AlliedModders, LLC.");
dvander@308: ConsolePrint(" Development would not have been possible without the following people:");
dvander@2905: ConsolePrint(" David \"BAILOPAN\" Anderson");
dvander@2905: ConsolePrint(" Matt \"pRED\" Woodrow");
dvander@2905: ConsolePrint(" Scott \"DS\" Ehlert");
dvander@2905: ConsolePrint(" Fyren");
dvander@3311: ConsolePrint(" Nicholas \"psychonic\" Hastings");
dvander@2905: ConsolePrint(" Borja \"faluco\" Ferrer");
dvander@2905: ConsolePrint(" Pavol \"PM OnoTo\" Marko");
dvander@3311: ConsolePrint(" Special thanks to asherkin, Liam, ferret, and Mani");
dvander@2905: ConsolePrint(" Special thanks to Viper and SteamFriends");
dvander@308: ConsolePrint(" http://www.sourcemod.net/");
dvander@2105: }
dvander@2105: else if (strcmp(cmdname, "version") == 0)
dvander@2105: {
dvander@308: ConsolePrint(" SourceMod Version Information:");
dvander@2784: ConsolePrint(" SourceMod Version: %s", SM_FULL_VERSION);
dvander@2193: ConsolePrint(" SourcePawn Engine: %s (build %s)", g_pSourcePawn2->GetEngineName(), g_pSourcePawn2->GetVersionString());
dvander@2193: ConsolePrint(" SourcePawn API: v1 = %d, v2 = %d", g_pSourcePawn->GetEngineAPIVersion(), g_pSourcePawn2->GetAPIVersion());
dvander@2105: ConsolePrint(" Compiled on: %s %s", __DATE__, __TIME__);
dvander@2281: ConsolePrint(" Build ID: %s", SM_BUILD_UNIQUEID);
dvander@308: ConsolePrint(" http://www.sourcemod.net/");
dvander@308: }
dvander@308: }
dvander@308:
dvander@308: CON_COMMAND(sm, "SourceMod Menu")
dvander@308: {
ds@2583: #if SOURCE_ENGINE <= SE_DARKMESSIAH
faluco@1541: CCommand args;
faluco@1541: #endif
faluco@1541: g_RootMenu.GotRootCmd(args);
dvander@308: }
dvander@900:
dvander@1687: FILE *g_pHndlLog = NULL;
dvander@1687:
dvander@1687: void write_handles_to_log(const char *fmt, ...)
dvander@1687: {
dvander@1687: va_list ap;
dvander@1687:
dvander@1687: va_start(ap, fmt);
dvander@1687: vfprintf(g_pHndlLog, fmt, ap);
dvander@1687: fprintf(g_pHndlLog, "\n");
dvander@1687: va_end(ap);
dvander@1687: }
dvander@1687:
dvander@1687: void write_handles_to_game(const char *fmt, ...)
dvander@1687: {
dvander@1687: size_t len;
dvander@1687: va_list ap;
dvander@1687: char buffer[1024];
dvander@1687:
dvander@1687: va_start(ap, fmt);
dvander@1687: len = UTIL_FormatArgs(buffer, sizeof(buffer)-2, fmt, ap);
dvander@1687: va_end(ap);
dvander@1687:
dvander@1687: buffer[len] = '\n';
dvander@1687: buffer[len+1] = '\0';
dvander@1687:
dvander@1687: engine->LogPrint(buffer);
dvander@1687: }
dvander@1687:
dvander@900: CON_COMMAND(sm_dump_handles, "Dumps Handle usage to a file for finding Handle leaks")
dvander@900: {
ds@2583: #if SOURCE_ENGINE <= SE_DARKMESSIAH
faluco@1541: CCommand args;
faluco@1541: #endif
faluco@1541: if (args.ArgC() < 2)
dvander@900: {
dvander@1687: g_RootMenu.ConsolePrint("Usage: sm_dump_handles or for game logs");
dvander@900: return;
dvander@900: }
dvander@900:
dvander@1687: if (strcmp(args.Arg(1), "log") != 0)
dvander@900: {
dvander@1687: const char *arg = args.Arg(1);
dvander@1687: FILE *fp = fopen(arg, "wt");
dvander@1687: if (!fp)
dvander@1687: {
dvander@1687: g_RootMenu.ConsolePrint("Could not find file \"%s\"", arg);
dvander@1687: return;
dvander@1687: }
dvander@900:
dvander@1687: g_pHndlLog = fp;
dvander@1687: g_HandleSys.Dump(write_handles_to_log);
dvander@1687: g_pHndlLog = NULL;
dvander@900:
dvander@1687: fclose(fp);
dvander@1687: }
dvander@1687: else
dvander@1687: {
dvander@1687: g_HandleSys.Dump(write_handles_to_game);
dvander@1687: }
dvander@900: }
dvander@2728: