/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ /* If you are missing that file, acquire a complete release at teeworlds.com. */ #include #include #include #include CConfiguration g_Config; class CConfig : public IConfig { IStorage *m_pStorage; IOHANDLE m_ConfigFile; bool m_Failed; struct CCallback { SAVECALLBACKFUNC m_pfnFunc; void *m_pUserData; }; enum { MAX_CALLBACKS = 16 }; CCallback m_aCallbacks[MAX_CALLBACKS]; int m_NumCallbacks; void EscapeParam(char *pDst, const char *pSrc, int Size) { str_escape(&pDst, pSrc, pDst + Size); } public: CConfig() { m_ConfigFile = 0; m_NumCallbacks = 0; m_Failed = false; } virtual void Init() { m_pStorage = Kernel()->RequestInterface(); Reset(); } virtual void Reset() { #define MACRO_CONFIG_INT(Name,ScriptName,def,min,max,flags,desc) g_Config.m_##Name = def; #define MACRO_CONFIG_COL(Name,ScriptName,def,flags,desc) MACRO_CONFIG_INT(Name,ScriptName,def,0,0,flags,desc) #define MACRO_CONFIG_STR(Name,ScriptName,len,def,flags,desc) str_copy(g_Config.m_##Name, def, len); #include "config_variables.h" #undef MACRO_CONFIG_INT #undef MACRO_CONFIG_COL #undef MACRO_CONFIG_STR } virtual void Save() { if(!m_pStorage || !g_Config.m_ClSaveSettings) return; char aConfigFileTmp[64]; str_format(aConfigFileTmp, sizeof(aConfigFileTmp), CONFIG_FILE ".%d.tmp", pid()); m_ConfigFile = m_pStorage->OpenFile(aConfigFileTmp, IOFLAG_WRITE, IStorage::TYPE_SAVE); if(!m_ConfigFile) return; m_Failed = false; char aLineBuf[1024*2]; char aEscapeBuf[1024*2]; #define MACRO_CONFIG_INT(Name,ScriptName,def,min,max,flags,desc) if((flags)&CFGFLAG_SAVE && g_Config.m_##Name != def) { str_format(aLineBuf, sizeof(aLineBuf), "%s %i", #ScriptName, g_Config.m_##Name); WriteLine(aLineBuf); } #define MACRO_CONFIG_COL(Name,ScriptName,def,flags,desc) if((flags)&CFGFLAG_SAVE && g_Config.m_##Name != def) { str_format(aLineBuf, sizeof(aLineBuf), "%s %u", #ScriptName, g_Config.m_##Name); WriteLine(aLineBuf); } #define MACRO_CONFIG_STR(Name,ScriptName,len,def,flags,desc) if((flags)&CFGFLAG_SAVE && str_comp(g_Config.m_##Name, def) != 0) { EscapeParam(aEscapeBuf, g_Config.m_##Name, sizeof(aEscapeBuf)); str_format(aLineBuf, sizeof(aLineBuf), "%s \"%s\"", #ScriptName, aEscapeBuf); WriteLine(aLineBuf); } #include "config_variables.h" #undef MACRO_CONFIG_INT #undef MACRO_CONFIG_COL #undef MACRO_CONFIG_STR for(int i = 0; i < m_NumCallbacks; i++) m_aCallbacks[i].m_pfnFunc(this, m_aCallbacks[i].m_pUserData); if(io_close(m_ConfigFile) != 0) m_Failed = true; m_ConfigFile = 0; if(m_Failed) { dbg_msg("config", "ERROR: writing to %s failed", aConfigFileTmp); return; } if(!m_pStorage->RenameFile(aConfigFileTmp, CONFIG_FILE, IStorage::TYPE_SAVE)) dbg_msg("config", "ERROR: renaming %s to " CONFIG_FILE " failed", aConfigFileTmp); } virtual void RegisterCallback(SAVECALLBACKFUNC pfnFunc, void *pUserData) { dbg_assert(m_NumCallbacks < MAX_CALLBACKS, "too many config callbacks"); m_aCallbacks[m_NumCallbacks].m_pfnFunc = pfnFunc; m_aCallbacks[m_NumCallbacks].m_pUserData = pUserData; m_NumCallbacks++; } virtual void WriteLine(const char *pLine) { if(!m_ConfigFile || io_write(m_ConfigFile, pLine, str_length(pLine)) != static_cast(str_length(pLine)) || #if defined(CONF_FAMILY_WINDOWS) io_write_newline(m_ConfigFile) != 2) #else io_write_newline(m_ConfigFile) != 1) #endif m_Failed = true; } }; IConfig *CreateConfig() { return new CConfig; }