changed the API around a bit to be more flexible

removed some ghastly unneeded stuff from the Translator
added Logger::LogFatal, experimental

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40669
This commit is contained in:
David Anderson 2007-04-05 05:25:11 +00:00
parent 3b9c8e1410
commit f93711bd82
11 changed files with 179 additions and 102 deletions

View File

@ -22,7 +22,7 @@
#ifdef PLATFORM_WINDOWS
ConVar sm_corecfgfile("sm_corecfgfile", "addons\\sourcemod\\configs\\core.cfg", 0, "SourceMod core configuration file");
#else
#elif defined PLATFORM_LINUX
ConVar sm_corecfgfile("sm_corecfgfile", "addons/sourcemod/configs/core.cfg", 0, "SourceMod core configuration file");
#endif
@ -45,21 +45,13 @@ void CoreConfig::OnRootConsoleCommand(const char *command, unsigned int argcount
const char *option = engine->Cmd_Argv(2);
const char *value = engine->Cmd_Argv(3);
CoreConfigErr err = SetConfigOption(option, value);
char error[255];
switch (err)
ConfigResult err = SetConfigOption(option, value, ConfigSource_Console, error, sizeof(error));
if (err == ConfigResult_Reject)
{
case CoreConfig_NoRuntime:
g_RootMenu.ConsolePrint("[SM] Cannot set \"%s\" while SourceMod is running.", option);
break;
case CoreConfig_InvalidValue:
g_RootMenu.ConsolePrint("[SM] Invalid value \"%s\" specified for configuration option \"%s\"", value, option);
break;
case CoreConfig_InvalidOption:
g_RootMenu.ConsolePrint("[SM] Invalid configuration option specified: %s", option);
break;
default:
break;
g_Logger.LogError("Could not set config option \"%s\" to \"%s\" (error: %s)", option, value, error);
}
return;
@ -90,44 +82,39 @@ void CoreConfig::Initialize()
!= SMCParse_Okay)
{
/* :TODO: This won't actually log or print anything :( - So fix that somehow */
g_Logger.LogError("[SM] Error encountered parsing core config file: %s", g_TextParser.GetSMCErrorString(err));
const char *error = g_TextParser.GetSMCErrorString(err);
g_Logger.LogFatal("[SM] Error encountered parsing core config file: %s", error ? error : "");
}
}
SMCParseResult CoreConfig::ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes)
{
CoreConfigErr err = SetConfigOption(key, value);
char error[255];
ConfigResult err = SetConfigOption(key, value, ConfigSource_File, error, sizeof(error));
if (err == CoreConfig_InvalidOption)
if (err == ConfigResult_Reject)
{
g_Logger.LogError("[SM] Warning: Ignoring invalid option \"%s\" in configuration file.", key);
} else if (err == CoreConfig_InvalidValue) {
g_Logger.LogError("[SM] Warning encountered parsing core configuration file.");
g_Logger.LogError("[SM] Invalid value \"%s\" specified for option \"%s\"", value, key);
/* This is a fatal error */
g_Logger.LogFatal("%s", error);
}
return SMCParse_Continue;
}
CoreConfigErr CoreConfig::SetConfigOption(const char *option, const char *value)
ConfigResult CoreConfig::SetConfigOption(const char *option, const char *value, ConfigSource source, char *error, size_t maxlength)
{
CoreConfigErr err = CoreConfig_TOTAL;
CoreConfigErr currentErr;
ConfigResult result;
/* Notify! */
SMGlobalClass *pBase = SMGlobalClass::head;
while (pBase)
{
currentErr = pBase->OnSourceModConfigChanged(option, value);
/* Lowest error code has priority */
if (currentErr < err)
if ((result = pBase->OnSourceModConfigChanged(option, value, source, error, maxlength)) != ConfigResult_Ignore)
{
err = currentErr;
return result;
}
pBase = pBase->m_pGlobalClassNext;
}
return err;
return ConfigResult_Ignore;
}

View File

@ -42,7 +42,7 @@ private:
/**
* Sets configuration option by notifying SourceMod components that rely on core.cfg
*/
CoreConfigErr SetConfigOption(const char *option, const char *value);
ConfigResult SetConfigOption(const char *option, const char *value, ConfigSource, char *Error, size_t maxlength);
};
extern CoreConfig g_CoreConfig;

View File

@ -15,6 +15,7 @@
#include <time.h>
#include "sourcemod.h"
#include "sourcemm_api.h"
#include "sm_stringutil.h"
#include "Logger.h"
#include "systems/LibrarySys.h"
#include "sm_version.h"
@ -25,31 +26,39 @@ Logger g_Logger;
* :TODO: This should be creating the log folder if it doesn't exist
*/
CoreConfigErr Logger::OnSourceModConfigChanged(const char *option, const char *value)
ConfigResult Logger::OnSourceModConfigChanged(const char *key,
const char *value,
ConfigSource source,
char *error,
size_t maxlength)
{
if (strcasecmp(option, "Logging") == 0)
if (strcasecmp(key, "Logging") == 0)
{
bool state = true;
if (strcasecmp(value, "on") == 0)
{
state = true;
} else if (strcasecmp(value, "off") == 0) {
state = false;
} else {
return CoreConfig_InvalidValue;
UTIL_Format(error, maxlength, "Invalid value: must be \"on\" or \"off\"");
return ConfigResult_Reject;
}
if (m_FirstPass)
if (source == ConfigSource_Console)
{
m_InitialState = state;
m_FirstPass = false;
if (state && !m_Active)
{
EnableLogging();
} else if (!state && m_Active) {
DisableLogging();
}
} else {
state ? g_Logger.EnableLogging() : g_Logger.DisableLogging();
m_InitialState = state;
}
return CoreConfig_Okay;
} else if (strcasecmp(option, "LogMode") == 0) {
return ConfigResult_Accept;
} else if (strcasecmp(key, "LogMode") == 0) {
if (strcasecmp(value, "daily") == 0)
{
m_Mode = LoggingMode_Daily;
@ -58,18 +67,19 @@ CoreConfigErr Logger::OnSourceModConfigChanged(const char *option, const char *v
} else if (strcasecmp(value, "game") == 0) {
m_Mode = LoggingMode_Game;
} else {
return CoreConfig_InvalidValue;
UTIL_Format(error, maxlength, "Invalid value: must be [daily|map|game]");
return ConfigResult_Reject;
}
return CoreConfig_Okay;
return ConfigResult_Accept;
}
return CoreConfig_InvalidOption;
return ConfigResult_Ignore;
}
void Logger::OnSourceModStartup(bool late)
{
InitLogger(m_Mode, m_InitialState);
InitLogger(m_Mode);
}
void Logger::OnSourceModAllShutdown()
@ -155,10 +165,10 @@ void Logger::_CloseFile()
m_ErrFileName.clear();
}
void Logger::InitLogger(LoggingMode mode, bool startlogging)
void Logger::InitLogger(LoggingMode mode)
{
m_Mode = mode;
m_Active = startlogging;
m_Active = m_InitialState;
time_t t;
time(&t);
@ -173,7 +183,7 @@ void Logger::InitLogger(LoggingMode mode, bool startlogging)
{
case LoggingMode_PerMap:
{
if (!startlogging)
if (!m_Active)
{
m_DelayedStart = true;
}
@ -414,3 +424,24 @@ void Logger::DisableLogging()
LogMessage("Logging disabled manually by user.");
m_Active = false;
}
void Logger::LogFatal(const char *msg, ...)
{
char path[PLATFORM_MAX_PATH];
g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "sourcemod_fatal.log");
FILE *fp = fopen(path, "at");
if (!fp)
{
/* We're just doomed, aren't we... */
return;
}
va_list ap;
va_start(ap, msg);
vfprintf(fp, msg, ap);
va_end(ap);
fputs("\n", fp);
fclose(fp);
}

View File

@ -36,18 +36,27 @@ enum LoggingMode
class Logger : public SMGlobalClass
{
public:
Logger() : m_Mode(LoggingMode_Daily), m_ErrMapStart(false), m_Active(false), m_DelayedStart(false), m_DailyPrintHdr(false), m_InitialState(true), m_FirstPass(true) {}
Logger() : m_Mode(LoggingMode_Daily), m_ErrMapStart(false),
m_Active(false), m_DelayedStart(false), m_DailyPrintHdr(false),
m_InitialState(true)
{
}
public: //SMGlobalClass
CoreConfigErr OnSourceModConfigChanged(const char *option, const char *value);
ConfigResult OnSourceModConfigChanged(const char *key,
const char *value,
ConfigSource source,
char *error,
size_t maxlength);
void OnSourceModStartup(bool late);
void OnSourceModAllShutdown();
public:
void InitLogger(LoggingMode mode, bool startlogging);
void InitLogger(LoggingMode mode);
void CloseLogger();
void EnableLogging();
void DisableLogging();
void LogMessage(const char *msg, ...);
void LogError(const char *msg, ...);
void LogFatal(const char *msg, ...);
void MapChange(const char *mapname);
const char *GetLogFileName(LogType type) const;
LoggingMode GetLoggingMode() const;
@ -66,7 +75,6 @@ private:
bool m_DelayedStart;
bool m_DailyPrintHdr;
bool m_InitialState;
bool m_FirstPass;
};
extern Logger g_Logger;

View File

@ -604,15 +604,30 @@ Translator::~Translator()
delete m_pStringTab;
}
CoreConfigErr Translator::OnSourceModConfigChanged(const char *option, const char *value)
ConfigResult Translator::OnSourceModConfigChanged(const char *key,
const char *value,
ConfigSource source,
char *error,
size_t maxlength)
{
if (strcasecmp(option, "ServerLang") == 0)
if (strcasecmp(value, "ServerLang") == 0)
{
if (source == ConfigSource_Console)
{
unsigned int index;
if (!GetLanguageByCode(value, &index))
{
UTIL_Format(error, maxlength, "Language code \"%s\" is not registered", value);
return ConfigResult_Reject;
}
}
strncopy(m_ServerLangCode, value, sizeof(m_ServerLangCode));
return CoreConfig_Okay;
return ConfigResult_Accept;
}
return CoreConfig_InvalidOption;
return ConfigResult_Ignore;
}
void Translator::OnSourceModAllInitialized()
@ -837,7 +852,20 @@ TransError Translator::CoreTrans(int client,
return Trans_Okay;
}
const char *Translator::GetServerLanguageCode() const
unsigned int Translator::GetServerLanguageCode()
{
return m_ServerLangCode;
void *serverLang;
/* :TODO: there is absolutely no reason this shouldn't be cached
* I don't even know why it was returning a string originally
*/
if (!sm_trie_retrieve(m_pLCodeLookup, m_ServerLangCode, &serverLang))
{
g_Logger.LogError("Server language was set to bad language \"%s\" -- reverting to English");
strncopy(m_ServerLangCode, "en", sizeof(m_ServerLangCode));
return 0;
}
return (unsigned int)serverLang;
}

View File

@ -49,6 +49,8 @@ struct Translation
int *fmt_order; /**< Format phrase order. */
};
#define LANGUAGE_ENGLISH 0
enum TransError
{
Trans_Okay = 0,
@ -100,7 +102,11 @@ public:
Translator();
~Translator();
public: // SMGlobalClass
CoreConfigErr OnSourceModConfigChanged(const char *option, const char *value);
ConfigResult OnSourceModConfigChanged(const char *key,
const char *value,
ConfigSource source,
char *error,
size_t maxlength);
void OnSourceModAllInitialized();
public: // ITextListener_SMC
void ReadSMC_ParseStart();
@ -121,7 +127,7 @@ public:
const char *phrase,
void **params,
size_t *outlen=NULL);
const char *GetServerLanguageCode() const;
unsigned int GetServerLanguageCode();
private:
bool AddLanguage(const char *langcode, const char *description);
private:

View File

@ -28,16 +28,19 @@ using namespace SourcePawn;
using namespace SourceMod;
/**
* @brief Lists error codes possible from attempting to set a core configuration option.
*/
enum CoreConfigErr
* @brief Lists error codes possible from attempting to set a core configuration option.
*/
enum ConfigResult
{
CoreConfig_Okay = 0, /**< No error */
CoreConfig_NoRuntime = 1, /**< Cannot set config option while SourceMod is running */
CoreConfig_InvalidValue = 2, /**< Invalid value specified for config option */
CoreConfig_InvalidOption = 3, /**< Invalid config option specified */
/* -------------------- */
CoreConfig_TOTAL /**< Total number of core config error codes */
ConfigResult_Accept = 0,
ConfigResult_Reject = 1,
ConfigResult_Ignore = 2
};
enum ConfigSource
{
ConfigSource_File = 0,
ConfigSource_Console = 1,
};
/**
@ -83,9 +86,13 @@ public:
* @note This is called once BEFORE OnSourceModStartup() when SourceMod is loading
* @note It can then be called again when the 'sm config' command is used
*/
virtual CoreConfigErr OnSourceModConfigChanged(const char *option, const char *value)
virtual ConfigResult OnSourceModConfigChanged(const char *key,
const char *value,
ConfigSource source,
char *error,
size_t maxlength)
{
return CoreConfig_InvalidOption;
return ConfigResult_Ignore;
}
private:
SMGlobalClass *m_pGlobalClassNext;

View File

@ -73,24 +73,9 @@ size_t Translate(char *buffer, size_t maxlen, IPluginContext *pCtx, const char *
try_serverlang:
if (target == LANG_SERVER)
{
langname = g_Translator.GetServerLanguageCode();
if (!TryServerLanguage(langname ? langname : "en", &langid))
{
pCtx->ThrowNativeError("Translation failure: English language not found");
goto error_out;
}
} else if ((target >= 1) && (target <= g_Players.GetMaxClients())) {
langname = g_Translator.GetServerLanguageCode(); /* :TODO: read player's lang */
if (!langname || !g_Translator.GetLanguageByCode(langname, &langid))
{
if (langname && !strcmp(langname, "en"))
{
pCtx->ThrowNativeError("Translation failure: English language not found");
goto error_out;
}
target = LANG_SERVER;
goto try_serverlang;
}
langid = g_Translator.GetServerLanguageCode();
} else if ((target >= 1) && (target <= g_Players.GetMaxClients())) {
langid = g_Translator.GetServerLanguageCode();
} else {
pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Translation failed: invalid client index %d", target);
goto error_out;
@ -102,9 +87,8 @@ try_serverlang:
{
target = LANG_SERVER;
goto try_serverlang;
} else {
if (!g_Translator.GetLanguageByCode("en", &langid)
|| !TryTranslation(pl, key, langid, langcount, &pTrans))
} else if (langid != LANGUAGE_ENGLISH) {
if (!TryTranslation(pl, key, LANGUAGE_ENGLISH, langcount, &pTrans))
{
pCtx->ThrowNativeErrorEx(SP_ERROR_PARAM, "Language phrase \"%s\" not found", key);
goto error_out;
@ -900,6 +884,19 @@ size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
}
}
size_t UTIL_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list ap)
{
size_t len = vsnprintf(buffer, maxlength, fmt, ap);
if (len >= maxlength)
{
buffer[maxlength - 1] = '\0';
return (maxlength - 1);
} else {
return len;
}
}
char *sm_strdup(const char *str)
{
char *ptr = new char[strlen(str)+1];

View File

@ -30,6 +30,7 @@ const char *stristr(const char *str, const char *substr);
unsigned int strncopy(char *dest, const char *src, size_t count);
size_t gnprintf(char *buffer, size_t maxlen, const char *format, void **args);
size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...);
size_t UTIL_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list ap);
char *sm_strdup(const char *str);
#endif // _INCLUDE_SOURCEMOD_STRINGUTIL_H_

View File

@ -69,24 +69,32 @@ SourceModBase::SourceModBase()
m_GotBasePath = false;
}
CoreConfigErr SourceModBase::OnSourceModConfigChanged(const char *option, const char *value)
ConfigResult SourceModBase::OnSourceModConfigChanged(const char *key,
const char *value,
ConfigSource source,
char *error,
size_t maxlength)
{
if (strcasecmp(option, "BasePath") == 0)
if (strcasecmp(value, "BasePath") == 0)
{
if (source == ConfigSource_Console)
{
UTIL_Format(error, maxlength, "Cannot be set at runtime");
return ConfigResult_Reject;
}
if (!m_GotBasePath)
{
g_LibSys.PathFormat(m_SMBaseDir, sizeof(m_SMBaseDir), "%s/%s", g_BaseDir.c_str(), value);
g_LibSys.PathFormat(m_SMRelDir, sizeof(m_SMRelDir), value);
m_GotBasePath = true;
return CoreConfig_Okay;
} else {
return CoreConfig_NoRuntime;
}
return ConfigResult_Accept;
}
return CoreConfig_InvalidOption;
return ConfigResult_Ignore;
}
bool SourceModBase::InitializeSourceMod(char *error, size_t err_max, bool late)
@ -97,7 +105,7 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t err_max, bool late)
g_CoreConfig.Initialize();
/* This shouldn't happen, but can't hurt to be safe */
if (!m_GotBasePath || !g_LibSys.PathExists(m_SMBaseDir))
if (!g_LibSys.PathExists(m_SMBaseDir) || !m_GotBasePath)
{
g_LibSys.PathFormat(m_SMBaseDir, sizeof(m_SMBaseDir), "%s/addons/sourcemod", g_BaseDir.c_str());
g_LibSys.PathFormat(m_SMRelDir, sizeof(m_SMRelDir), "addons/sourcemod");

View File

@ -78,7 +78,11 @@ public:
*/
void SetAuthChecking(bool set);
public: // SMGlobalClass
CoreConfigErr OnSourceModConfigChanged(const char *option, const char *value);
ConfigResult OnSourceModConfigChanged(const char *key,
const char *value,
ConfigSource source,
char *error,
size_t maxlength);
public: // ISourceMod
const char *GetModPath() const;
const char *GetSourceModPath() const;