fixed a number of memory complaints from valgrind. most of these were minor, but there was a rather disturbing memory over-read error in the SMC text parser. correcting this brought about a rewrite of its API. this change is BACKWARDS INCOMPATIBLE for C++ extensions, but it was sorely needed, and the API is now both future-extensible and much easier to work with. plugins didn't need any changes, but they will probably get the better API changes in a future release. as a special bonus, the RawLine() hook is now much less expensive since the entire stream buffer won't be shoved through it like before!
--HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401662
This commit is contained in:
parent
e425558f3f
commit
172f28d676
@ -82,22 +82,21 @@ public:
|
|||||||
private:
|
private:
|
||||||
bool Parse()
|
bool Parse()
|
||||||
{
|
{
|
||||||
unsigned int line = 0;
|
SMCStates states;
|
||||||
SMCParseError error;
|
SMCError error;
|
||||||
|
|
||||||
m_Line = 0;
|
|
||||||
m_bFileNameLogged = false;
|
m_bFileNameLogged = false;
|
||||||
g_SourceMod.BuildPath(Path_SM, m_File, sizeof(m_File), "configs/admin_levels.cfg");
|
g_SourceMod.BuildPath(Path_SM, m_File, sizeof(m_File), "configs/admin_levels.cfg");
|
||||||
|
|
||||||
if ((error = textparsers->ParseFile_SMC(m_File, this, &line, NULL))
|
if ((error = textparsers->ParseFile_SMC(m_File, this, &states))
|
||||||
!= SMCParse_Okay)
|
!= SMCError_Okay)
|
||||||
{
|
{
|
||||||
const char *err_string = textparsers->GetSMCErrorString(error);
|
const char *err_string = textparsers->GetSMCErrorString(error);
|
||||||
if (!err_string)
|
if (!err_string)
|
||||||
{
|
{
|
||||||
err_string = "Unknown error";
|
err_string = "Unknown error";
|
||||||
}
|
}
|
||||||
ParseError("Error %d (%s)", error, err_string);
|
ParseError(NULL, "Error %d (%s)", error, err_string);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,12 +108,12 @@ private:
|
|||||||
m_IgnoreLevel = 0;
|
m_IgnoreLevel = 0;
|
||||||
memset(g_FlagSet, 0, sizeof(g_FlagSet));
|
memset(g_FlagSet, 0, sizeof(g_FlagSet));
|
||||||
}
|
}
|
||||||
SMCParseResult ReadSMC_NewSection(const char *name, bool opt_quotes)
|
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name)
|
||||||
{
|
{
|
||||||
if (m_IgnoreLevel)
|
if (m_IgnoreLevel)
|
||||||
{
|
{
|
||||||
m_IgnoreLevel++;
|
m_IgnoreLevel++;
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_LevelState == LEVEL_STATE_NONE)
|
if (m_LevelState == LEVEL_STATE_NONE)
|
||||||
@ -122,35 +121,41 @@ private:
|
|||||||
if (strcmp(name, "Levels") == 0)
|
if (strcmp(name, "Levels") == 0)
|
||||||
{
|
{
|
||||||
m_LevelState = LEVEL_STATE_LEVELS;
|
m_LevelState = LEVEL_STATE_LEVELS;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
m_IgnoreLevel++;
|
m_IgnoreLevel++;
|
||||||
}
|
}
|
||||||
} else if (m_LevelState == LEVEL_STATE_LEVELS) {
|
} else if (m_LevelState == LEVEL_STATE_LEVELS) {
|
||||||
if (strcmp(name, "Flags") == 0)
|
if (strcmp(name, "Flags") == 0)
|
||||||
{
|
{
|
||||||
m_LevelState = LEVEL_STATE_FLAGS;
|
m_LevelState = LEVEL_STATE_FLAGS;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
m_IgnoreLevel++;
|
m_IgnoreLevel++;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
m_IgnoreLevel++;
|
m_IgnoreLevel++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
SMCParseResult ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes)
|
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
|
||||||
{
|
{
|
||||||
if (m_LevelState != LEVEL_STATE_FLAGS || m_IgnoreLevel)
|
if (m_LevelState != LEVEL_STATE_FLAGS || m_IgnoreLevel)
|
||||||
{
|
{
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char c = (unsigned)value[0];
|
unsigned char c = (unsigned)value[0];
|
||||||
|
|
||||||
if (c < (unsigned)'a' || c > (unsigned)'z')
|
if (c < (unsigned)'a' || c > (unsigned)'z')
|
||||||
{
|
{
|
||||||
ParseError("Flag \"%c\" is not a lower-case ASCII letter", c);
|
ParseError(states, "Flag \"%c\" is not a lower-case ASCII letter", c);
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
c -= (unsigned)'a';
|
c -= (unsigned)'a';
|
||||||
@ -159,38 +164,35 @@ private:
|
|||||||
|
|
||||||
if (!g_Admins.FindFlag(key, &g_FlagLetters[c]))
|
if (!g_Admins.FindFlag(key, &g_FlagLetters[c]))
|
||||||
{
|
{
|
||||||
ParseError("Unrecognized admin level \"%s\"", key);
|
ParseError(states, "Unrecognized admin level \"%s\"", key);
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_FlagSet[c] = true;
|
g_FlagSet[c] = true;
|
||||||
|
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
SMCParseResult ReadSMC_LeavingSection()
|
SMCResult ReadSMC_LeavingSection(const SMCStates *states)
|
||||||
{
|
{
|
||||||
if (m_IgnoreLevel)
|
if (m_IgnoreLevel)
|
||||||
{
|
{
|
||||||
m_IgnoreLevel--;
|
m_IgnoreLevel--;
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_LevelState == LEVEL_STATE_FLAGS)
|
if (m_LevelState == LEVEL_STATE_FLAGS)
|
||||||
{
|
{
|
||||||
m_LevelState = LEVEL_STATE_LEVELS;
|
m_LevelState = LEVEL_STATE_LEVELS;
|
||||||
return SMCParse_Halt;
|
return SMCResult_Halt;
|
||||||
} else if (m_LevelState == LEVEL_STATE_LEVELS) {
|
}
|
||||||
|
else if (m_LevelState == LEVEL_STATE_LEVELS)
|
||||||
|
{
|
||||||
m_LevelState = LEVEL_STATE_NONE;
|
m_LevelState = LEVEL_STATE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
SMCParseResult ReadSMC_RawLine(const char *line, unsigned int curline)
|
void ParseError(const SMCStates *states, const char *message, ...)
|
||||||
{
|
|
||||||
m_Line = curline;
|
|
||||||
return SMCParse_Continue;
|
|
||||||
}
|
|
||||||
void ParseError(const char *message, ...)
|
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
@ -205,14 +207,13 @@ private:
|
|||||||
m_bFileNameLogged = true;
|
m_bFileNameLogged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_Logger.LogError("[SM] (Line %d): %s", m_Line, buffer);
|
g_Logger.LogError("[SM] (Line %d): %s", states ? states->line : 0, buffer);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
bool m_bFileNameLogged;
|
bool m_bFileNameLogged;
|
||||||
char m_File[PLATFORM_MAX_PATH];
|
char m_File[PLATFORM_MAX_PATH];
|
||||||
int m_LevelState;
|
int m_LevelState;
|
||||||
int m_IgnoreLevel;
|
int m_IgnoreLevel;
|
||||||
unsigned int m_Line;
|
|
||||||
} s_FlagReader;
|
} s_FlagReader;
|
||||||
|
|
||||||
AdminCache::AdminCache()
|
AdminCache::AdminCache()
|
||||||
|
@ -100,7 +100,7 @@ void CoreConfig::OnRootConsoleCommand(const char *cmdname, const CCommand &comma
|
|||||||
|
|
||||||
void CoreConfig::Initialize()
|
void CoreConfig::Initialize()
|
||||||
{
|
{
|
||||||
SMCParseError err;
|
SMCError err;
|
||||||
char filePath[PLATFORM_MAX_PATH];
|
char filePath[PLATFORM_MAX_PATH];
|
||||||
|
|
||||||
/* Try to get command line value of core config convar */
|
/* Try to get command line value of core config convar */
|
||||||
@ -116,7 +116,7 @@ void CoreConfig::Initialize()
|
|||||||
g_LibSys.PathFormat(filePath, sizeof(filePath), "%s/%s", g_SourceMod.GetGamePath(), corecfg);
|
g_LibSys.PathFormat(filePath, sizeof(filePath), "%s/%s", g_SourceMod.GetGamePath(), corecfg);
|
||||||
|
|
||||||
/* Parse config file */
|
/* Parse config file */
|
||||||
if ((err=textparsers->ParseFile_SMC(filePath, this, NULL, NULL)) != SMCParse_Okay)
|
if ((err=textparsers->ParseFile_SMC(filePath, this, NULL)) != SMCError_Okay)
|
||||||
{
|
{
|
||||||
/* :TODO: This won't actually log or print anything :( - So fix that somehow */
|
/* :TODO: This won't actually log or print anything :( - So fix that somehow */
|
||||||
const char *error = textparsers->GetSMCErrorString(err);
|
const char *error = textparsers->GetSMCErrorString(err);
|
||||||
@ -124,7 +124,7 @@ void CoreConfig::Initialize()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SMCParseResult CoreConfig::ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes)
|
SMCResult CoreConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
|
||||||
{
|
{
|
||||||
char error[255];
|
char error[255];
|
||||||
ConfigResult err = SetConfigOption(key, value, ConfigSource_File, error, sizeof(error));
|
ConfigResult err = SetConfigOption(key, value, ConfigSource_File, error, sizeof(error));
|
||||||
@ -135,7 +135,7 @@ SMCParseResult CoreConfig::ReadSMC_KeyValue(const char *key, const char *value,
|
|||||||
g_Logger.LogFatal("Config error (key: %s) (value: %s) %s", key, value, error);
|
g_Logger.LogFatal("Config error (key: %s) (value: %s) %s", key, value, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigResult CoreConfig::SetConfigOption(const char *option, const char *value, ConfigSource source, char *error, size_t maxlength)
|
ConfigResult CoreConfig::SetConfigOption(const char *option, const char *value, ConfigSource source, char *error, size_t maxlength)
|
||||||
|
@ -48,7 +48,7 @@ public: // SMGlobalClass
|
|||||||
void OnSourceModShutdown();
|
void OnSourceModShutdown();
|
||||||
void OnSourceModLevelChange(const char *mapName);
|
void OnSourceModLevelChange(const char *mapName);
|
||||||
public: // ITextListener_SMC
|
public: // ITextListener_SMC
|
||||||
SMCParseResult ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes);
|
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
|
||||||
public: // IRootConsoleCommand
|
public: // IRootConsoleCommand
|
||||||
void OnRootConsoleCommand(const char *cmdname, const CCommand &command);
|
void OnRootConsoleCommand(const char *cmdname, const CCommand &command);
|
||||||
public:
|
public:
|
||||||
|
@ -75,21 +75,21 @@ void DBManager::OnSourceModAllInitialized()
|
|||||||
|
|
||||||
void DBManager::OnSourceModLevelChange(const char *mapName)
|
void DBManager::OnSourceModLevelChange(const char *mapName)
|
||||||
{
|
{
|
||||||
SMCParseError err;
|
SMCError err;
|
||||||
unsigned int line = 0;
|
SMCStates states = {0, 0};
|
||||||
|
|
||||||
/* We lock and don't give up the lock until we're done.
|
/* We lock and don't give up the lock until we're done.
|
||||||
* This way the thread's search won't be searching through a
|
* This way the thread's search won't be searching through a
|
||||||
* potentially empty/corrupt list, which would be very bad.
|
* potentially empty/corrupt list, which would be very bad.
|
||||||
*/
|
*/
|
||||||
m_pConfigLock->Lock();
|
m_pConfigLock->Lock();
|
||||||
if ((err = textparsers->ParseFile_SMC(m_Filename, this, &line, NULL)) != SMCParse_Okay)
|
if ((err = textparsers->ParseFile_SMC(m_Filename, this, &states)) != SMCError_Okay)
|
||||||
{
|
{
|
||||||
g_Logger.LogError("[SM] Detected parse error(s) in file \"%s\"", m_Filename);
|
g_Logger.LogError("[SM] Detected parse error(s) in file \"%s\"", m_Filename);
|
||||||
if (err != SMCParse_Custom)
|
if (err != SMCError_Custom)
|
||||||
{
|
{
|
||||||
const char *txt = textparsers->GetSMCErrorString(err);
|
const char *txt = textparsers->GetSMCErrorString(err);
|
||||||
g_Logger.LogError("[SM] Line %d: %s", line, txt);
|
g_Logger.LogError("[SM] Line %d: %s", states.line, txt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_pConfigLock->Unlock();
|
m_pConfigLock->Unlock();
|
||||||
@ -141,12 +141,12 @@ void DBManager::ReadSMC_ParseStart()
|
|||||||
}
|
}
|
||||||
|
|
||||||
ConfDbInfo s_CurInfo;
|
ConfDbInfo s_CurInfo;
|
||||||
SMCParseResult DBManager::ReadSMC_NewSection(const char *name, bool opt_quotes)
|
SMCResult DBManager::ReadSMC_NewSection(const SMCStates *states, const char *name)
|
||||||
{
|
{
|
||||||
if (m_ParseLevel)
|
if (m_ParseLevel)
|
||||||
{
|
{
|
||||||
m_ParseLevel++;
|
m_ParseLevel++;
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_ParseState == DBPARSE_LEVEL_NONE)
|
if (m_ParseState == DBPARSE_LEVEL_NONE)
|
||||||
@ -165,14 +165,14 @@ SMCParseResult DBManager::ReadSMC_NewSection(const char *name, bool opt_quotes)
|
|||||||
m_ParseLevel++;
|
m_ParseLevel++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
SMCParseResult DBManager::ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes)
|
SMCResult DBManager::ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
|
||||||
{
|
{
|
||||||
if (m_ParseLevel)
|
if (m_ParseLevel)
|
||||||
{
|
{
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_ParseState == DBPARSE_LEVEL_MAIN)
|
if (m_ParseState == DBPARSE_LEVEL_MAIN)
|
||||||
@ -203,7 +203,7 @@ SMCParseResult DBManager::ReadSMC_KeyValue(const char *key, const char *value, b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ASSIGN_VAR(var) \
|
#define ASSIGN_VAR(var) \
|
||||||
@ -213,12 +213,12 @@ SMCParseResult DBManager::ReadSMC_KeyValue(const char *key, const char *value, b
|
|||||||
s_CurInfo.info.var = m_StrTab.GetString(s_CurInfo.var); \
|
s_CurInfo.info.var = m_StrTab.GetString(s_CurInfo.var); \
|
||||||
}
|
}
|
||||||
|
|
||||||
SMCParseResult DBManager::ReadSMC_LeavingSection()
|
SMCResult DBManager::ReadSMC_LeavingSection(const SMCStates *states)
|
||||||
{
|
{
|
||||||
if (m_ParseLevel)
|
if (m_ParseLevel)
|
||||||
{
|
{
|
||||||
m_ParseLevel--;
|
m_ParseLevel--;
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_ParseState == DBPARSE_LEVEL_DATABASE)
|
if (m_ParseState == DBPARSE_LEVEL_DATABASE)
|
||||||
@ -239,10 +239,10 @@ SMCParseResult DBManager::ReadSMC_LeavingSection()
|
|||||||
m_ParseState = DBPARSE_LEVEL_MAIN;
|
m_ParseState = DBPARSE_LEVEL_MAIN;
|
||||||
} else if (m_ParseState == DBPARSE_LEVEL_MAIN) {
|
} else if (m_ParseState == DBPARSE_LEVEL_MAIN) {
|
||||||
m_ParseState = DBPARSE_LEVEL_NONE;
|
m_ParseState = DBPARSE_LEVEL_NONE;
|
||||||
return SMCParse_Halt;
|
return SMCResult_Halt;
|
||||||
}
|
}
|
||||||
|
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
#undef ASSIGN_VAR
|
#undef ASSIGN_VAR
|
||||||
|
|
||||||
|
@ -94,9 +94,9 @@ public: //IDBManager
|
|||||||
HandleError ReleaseHandle(Handle_t hndl, DBHandleType type, IdentityToken_t *token);
|
HandleError ReleaseHandle(Handle_t hndl, DBHandleType type, IdentityToken_t *token);
|
||||||
public: //ITextListener_SMC
|
public: //ITextListener_SMC
|
||||||
void ReadSMC_ParseStart();
|
void ReadSMC_ParseStart();
|
||||||
SMCParseResult ReadSMC_NewSection(const char *name, bool opt_quotes);
|
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
|
||||||
SMCParseResult ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes);
|
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
|
||||||
SMCParseResult ReadSMC_LeavingSection();
|
SMCResult ReadSMC_LeavingSection(const SMCStates *states);
|
||||||
void ReadSMC_ParseEnd(bool halted, bool failed);
|
void ReadSMC_ParseEnd(bool halted, bool failed);
|
||||||
public: //IThread
|
public: //IThread
|
||||||
void RunThread(IThreadHandle *pThread);
|
void RunThread(IThreadHandle *pThread);
|
||||||
|
@ -106,12 +106,12 @@ CGameConfig::~CGameConfig()
|
|||||||
delete m_pStrings;
|
delete m_pStrings;
|
||||||
}
|
}
|
||||||
|
|
||||||
SMCParseResult CGameConfig::ReadSMC_NewSection(const char *name, bool opt_quotes)
|
SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *name)
|
||||||
{
|
{
|
||||||
if (m_IgnoreLevel)
|
if (m_IgnoreLevel)
|
||||||
{
|
{
|
||||||
m_IgnoreLevel++;
|
m_IgnoreLevel++;
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (m_ParseState)
|
switch (m_ParseState)
|
||||||
@ -245,14 +245,14 @@ SMCParseResult CGameConfig::ReadSMC_NewSection(const char *name, bool opt_quotes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
SMCParseResult CGameConfig::ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes)
|
SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
|
||||||
{
|
{
|
||||||
if (m_IgnoreLevel)
|
if (m_IgnoreLevel)
|
||||||
{
|
{
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_ParseState == PSTATE_GAMEDEFS_OFFSETS_OFFSET)
|
if (m_ParseState == PSTATE_GAMEDEFS_OFFSETS_OFFSET)
|
||||||
@ -296,15 +296,15 @@ SMCParseResult CGameConfig::ReadSMC_KeyValue(const char *key, const char *value,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
SMCParseResult CGameConfig::ReadSMC_LeavingSection()
|
SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
|
||||||
{
|
{
|
||||||
if (m_IgnoreLevel)
|
if (m_IgnoreLevel)
|
||||||
{
|
{
|
||||||
m_IgnoreLevel--;
|
m_IgnoreLevel--;
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (m_ParseState)
|
switch (m_ParseState)
|
||||||
@ -478,12 +478,12 @@ skip_find:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CGameConfig::Reparse(char *error, size_t maxlength)
|
bool CGameConfig::Reparse(char *error, size_t maxlength)
|
||||||
{
|
{
|
||||||
SMCParseError err;
|
SMCError err;
|
||||||
|
|
||||||
char path[PLATFORM_MAX_PATH];
|
char path[PLATFORM_MAX_PATH];
|
||||||
g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "gamedata/%s.txt", m_pFile);
|
g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "gamedata/%s.txt", m_pFile);
|
||||||
@ -503,10 +503,10 @@ bool CGameConfig::Reparse(char *error, size_t maxlength)
|
|||||||
sm_trie_clear(m_pProps);
|
sm_trie_clear(m_pProps);
|
||||||
sm_trie_clear(m_pKeys);
|
sm_trie_clear(m_pKeys);
|
||||||
|
|
||||||
if ((err=textparsers->ParseFile_SMC(path, this, NULL, NULL))
|
if ((err=textparsers->ParseFile_SMC(path, this, NULL))
|
||||||
!= SMCParse_Okay)
|
!= SMCError_Okay)
|
||||||
{
|
{
|
||||||
if (error && (err != SMCParse_Custom))
|
if (error && (err != SMCError_Custom))
|
||||||
{
|
{
|
||||||
const char *str = textparsers->GetSMCErrorString(err);
|
const char *str = textparsers->GetSMCErrorString(err);
|
||||||
snprintf(error, maxlength, "%s", str);
|
snprintf(error, maxlength, "%s", str);
|
||||||
|
@ -55,9 +55,9 @@ public:
|
|||||||
public:
|
public:
|
||||||
bool Reparse(char *error, size_t maxlength);
|
bool Reparse(char *error, size_t maxlength);
|
||||||
public: //ITextListener_SMC
|
public: //ITextListener_SMC
|
||||||
SMCParseResult ReadSMC_NewSection(const char *name, bool opt_quotes);
|
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
|
||||||
SMCParseResult ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes);
|
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
|
||||||
SMCParseResult ReadSMC_LeavingSection();
|
SMCResult ReadSMC_LeavingSection(const SMCStates *states);
|
||||||
public: //IGameConfig
|
public: //IGameConfig
|
||||||
const char *GetKeyValue(const char *key);
|
const char *GetKeyValue(const char *key);
|
||||||
bool GetOffset(const char *key, int *value);
|
bool GetOffset(const char *key, int *value);
|
||||||
|
@ -107,14 +107,13 @@ bool CharStreamReader(void *stream, char *buffer, size_t maxlength, unsigned int
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
SMCParseError TextParsers::ParseString_SMC(const char *stream,
|
SMCError TextParsers::ParseString_SMC(const char *stream,
|
||||||
ITextListener_SMC *smc,
|
ITextListener_SMC *smc,
|
||||||
unsigned int *line,
|
SMCStates *states)
|
||||||
unsigned int *col)
|
|
||||||
{
|
{
|
||||||
CharStream srdr = { stream };
|
CharStream srdr = { stream };
|
||||||
|
|
||||||
return ParseStream_SMC(&srdr, CharStreamReader, smc, line, col);
|
return ParseStream_SMC(&srdr, CharStreamReader, smc, states);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -135,16 +134,21 @@ bool FileStreamReader(void *stream, char *buffer, size_t maxlength, unsigned int
|
|||||||
return (ferror((FILE *)stream) == 0);
|
return (ferror((FILE *)stream) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
SMCParseError TextParsers::ParseFile_SMC(const char *file, ITextListener_SMC *smc, unsigned int *line, unsigned int *col)
|
SMCError TextParsers::ParseFile_SMC(const char *file, ITextListener_SMC *smc, SMCStates *states)
|
||||||
{
|
{
|
||||||
FILE *fp = fopen(file, "rt");
|
FILE *fp = fopen(file, "rt");
|
||||||
|
|
||||||
if (!fp)
|
if (!fp)
|
||||||
{
|
{
|
||||||
return SMCParse_StreamOpen;
|
if (states != NULL)
|
||||||
|
{
|
||||||
|
states->line = 0;
|
||||||
|
states->col = 0;
|
||||||
|
}
|
||||||
|
return SMCError_StreamOpen;
|
||||||
}
|
}
|
||||||
|
|
||||||
SMCParseError result = ParseStream_SMC(fp, FileStreamReader, smc, line, col);
|
SMCError result = ParseStream_SMC(fp, FileStreamReader, smc, states);
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
@ -273,34 +277,44 @@ char *lowstring(StringInfo info[3])
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
SMCParseError TextParsers::ParseStream_SMC(void *stream,
|
SMCError TextParsers::ParseStream_SMC(void *stream,
|
||||||
STREAMREADER srdr,
|
STREAMREADER srdr,
|
||||||
ITextListener_SMC *smc,
|
ITextListener_SMC *smc,
|
||||||
unsigned int *line,
|
SMCStates *pStates)
|
||||||
unsigned int *col)
|
|
||||||
{
|
{
|
||||||
char *reparse_point = NULL;
|
char *reparse_point = NULL;
|
||||||
char in_buf[4096];
|
char in_buf[4096];
|
||||||
char *parse_point = in_buf;
|
char *parse_point = in_buf;
|
||||||
char *line_begin = in_buf;
|
char *line_begin = in_buf;
|
||||||
unsigned int read;
|
unsigned int read;
|
||||||
unsigned int curline = 1;
|
|
||||||
unsigned int curtok = 0;
|
|
||||||
unsigned int curlevel = 0;
|
unsigned int curlevel = 0;
|
||||||
bool in_quote = false;
|
bool in_quote = false;
|
||||||
bool ignoring = false;
|
bool ignoring = false;
|
||||||
bool eol_comment = false;
|
bool eol_comment = false;
|
||||||
bool ml_comment = false;
|
bool ml_comment = false;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
SMCParseError err = SMCParse_Okay;
|
SMCError err = SMCError_Okay;
|
||||||
SMCParseResult res;
|
SMCResult res;
|
||||||
|
SMCStates states;
|
||||||
char c;
|
char c;
|
||||||
|
|
||||||
StringInfo strings[3];
|
StringInfo strings[3];
|
||||||
StringInfo emptystring;
|
StringInfo emptystring;
|
||||||
|
|
||||||
|
states.line = 1;
|
||||||
|
states.col = 0;
|
||||||
|
|
||||||
smc->ReadSMC_ParseStart();
|
smc->ReadSMC_ParseStart();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The stream reader reads in as much as it can fill the buffer with.
|
||||||
|
* It then processes the buffer. If the buffer cannot be fully processed, for example,
|
||||||
|
* a line is left hanging with no newline, then the contents of the buffer is shifted
|
||||||
|
* down, and the buffer is filled from the stream reader again.
|
||||||
|
*
|
||||||
|
* What makes this particularly annoying is that we cache pointers everywhere, so when
|
||||||
|
* the shifting process takes place, all those pointers must be shifted as well.
|
||||||
|
*/
|
||||||
while (srdr(stream, parse_point, sizeof(in_buf) - (parse_point - in_buf) - 1, &read))
|
while (srdr(stream, parse_point, sizeof(in_buf) - (parse_point - in_buf) - 1, &read))
|
||||||
{
|
{
|
||||||
if (!read)
|
if (!read)
|
||||||
@ -308,10 +322,10 @@ SMCParseError TextParsers::ParseStream_SMC(void *stream,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* :TODO: do this outside of the main loop somehow
|
/* Check for BOM markings, which is only relevant on the first line.
|
||||||
* This checks for BOM markings
|
* Not worth it, but it could be moved out of the loop.
|
||||||
*/
|
*/
|
||||||
if (curline == 1 &&
|
if (states.line == 1 &&
|
||||||
in_buf[0] == (char)0xEF &&
|
in_buf[0] == (char)0xEF &&
|
||||||
in_buf[1] == (char)0xBB &&
|
in_buf[1] == (char)0xBB &&
|
||||||
in_buf[2] == (char)0xBF)
|
in_buf[2] == (char)0xBF)
|
||||||
@ -341,7 +355,7 @@ SMCParseError TextParsers::ParseStream_SMC(void *stream,
|
|||||||
strings[0].end = &parse_point[i];
|
strings[0].end = &parse_point[i];
|
||||||
if (rotate(strings) != NULL)
|
if (rotate(strings) != NULL)
|
||||||
{
|
{
|
||||||
err = SMCParse_InvalidTokens;
|
err = SMCError_InvalidTokens;
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -354,39 +368,44 @@ SMCParseError TextParsers::ParseStream_SMC(void *stream,
|
|||||||
ignoring = false;
|
ignoring = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pass the raw line onto the listener */
|
/* Pass the raw line onto the listener. We terminate the line so the receiver
|
||||||
if ((res=smc->ReadSMC_RawLine(line_begin, curline)) != SMCParse_Continue)
|
* doesn't get tons of useless info. We restore the newline after.
|
||||||
|
*/
|
||||||
|
parse_point[i] = '\0';
|
||||||
|
if ((res=smc->ReadSMC_RawLine(&states, line_begin)) != SMCResult_Continue)
|
||||||
{
|
{
|
||||||
err = (res == SMCParse_HaltFail) ? SMCParse_Custom : SMCParse_Okay;
|
err = (res == SMCResult_HaltFail) ? SMCError_Custom : SMCError_Okay;
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
parse_point[i] = '\n';
|
||||||
|
|
||||||
/* Now we check the sanity of our staged strings! */
|
/* Now we check the sanity of our staged strings! */
|
||||||
if (strings[2].ptr)
|
if (strings[2].ptr)
|
||||||
{
|
{
|
||||||
if (!curlevel)
|
if (!curlevel)
|
||||||
{
|
{
|
||||||
err = SMCParse_InvalidProperty1;
|
err = SMCError_InvalidProperty1;
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
/* Assume the next string is a property and pass the info on. */
|
/* Assume the next string is a property and pass the info on. */
|
||||||
if ((res=smc->ReadSMC_KeyValue(
|
if ((res=smc->ReadSMC_KeyValue(
|
||||||
|
&states,
|
||||||
FixupString(strings[2]),
|
FixupString(strings[2]),
|
||||||
FixupString(strings[1]),
|
FixupString(strings[1]))) != SMCResult_Continue)
|
||||||
strings[2].quoted,
|
|
||||||
strings[1].quoted)) != SMCParse_Continue)
|
|
||||||
{
|
{
|
||||||
err = (res == SMCParse_HaltFail) ? SMCParse_Custom : SMCParse_Okay;
|
err = (res == SMCResult_HaltFail) ? SMCError_Custom : SMCError_Okay;
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
scrap(strings);
|
scrap(strings);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Change the states for the next line */
|
/* Change the states for the next line */
|
||||||
curtok = 0;
|
states.col = 0;
|
||||||
curline++;
|
states.line++;
|
||||||
line_begin = &parse_point[i+1]; //Note: safe because this gets relocated later
|
line_begin = &parse_point[i+1]; //Note: safe because this gets relocated later
|
||||||
} else if (ignoring) {
|
}
|
||||||
|
else if (ignoring)
|
||||||
|
{
|
||||||
if (in_quote)
|
if (in_quote)
|
||||||
{
|
{
|
||||||
/* If i was 0, this case is impossible due to reparsing */
|
/* If i was 0, this case is impossible due to reparsing */
|
||||||
@ -403,10 +422,12 @@ SMCParseError TextParsers::ParseStream_SMC(void *stream,
|
|||||||
if (rotate(strings) != NULL)
|
if (rotate(strings) != NULL)
|
||||||
{
|
{
|
||||||
/* If we rotated too many strings, there was too much crap on one line */
|
/* If we rotated too many strings, there was too much crap on one line */
|
||||||
err = SMCParse_InvalidTokens;
|
err = SMCError_InvalidTokens;
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
} else if (c == '\\') {
|
}
|
||||||
|
else if (c == '\\')
|
||||||
|
{
|
||||||
strings[0].special = true;
|
strings[0].special = true;
|
||||||
if (i == (read - 1))
|
if (i == (read - 1))
|
||||||
{
|
{
|
||||||
@ -414,7 +435,9 @@ SMCParseError TextParsers::ParseStream_SMC(void *stream,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (ml_comment) {
|
}
|
||||||
|
else if (ml_comment)
|
||||||
|
{
|
||||||
if (c == '*')
|
if (c == '*')
|
||||||
{
|
{
|
||||||
/* Check if we need to get more input first */
|
/* Check if we need to get more input first */
|
||||||
@ -431,11 +454,13 @@ SMCParseError TextParsers::ParseStream_SMC(void *stream,
|
|||||||
assert(strings[0].ptr == NULL);
|
assert(strings[0].ptr == NULL);
|
||||||
/* Advance the input stream so we don't choke on this token */
|
/* Advance the input stream so we don't choke on this token */
|
||||||
i++;
|
i++;
|
||||||
curtok++;
|
states.col++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* Check if we're whitespace or not */
|
/* Check if we're whitespace or not */
|
||||||
if (!g_ws_chartable[(unsigned)c])
|
if (!g_ws_chartable[(unsigned)c])
|
||||||
{
|
{
|
||||||
@ -468,7 +493,9 @@ SMCParseError TextParsers::ParseStream_SMC(void *stream,
|
|||||||
ignoring = true;
|
ignoring = true;
|
||||||
eol_comment = true;
|
eol_comment = true;
|
||||||
restage = true;
|
restage = true;
|
||||||
} else if (parse_point[i+1] == '*') {
|
}
|
||||||
|
else if (parse_point[i+1] == '*')
|
||||||
|
{
|
||||||
/* inline comment - start ignoring */
|
/* inline comment - start ignoring */
|
||||||
ignoring = true;
|
ignoring = true;
|
||||||
ml_comment = true;
|
ml_comment = true;
|
||||||
@ -479,93 +506,108 @@ SMCParseError TextParsers::ParseStream_SMC(void *stream,
|
|||||||
*/
|
*/
|
||||||
restage = true;
|
restage = true;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ignoring = true;
|
ignoring = true;
|
||||||
eol_comment = true;
|
eol_comment = true;
|
||||||
restage = true;
|
restage = true;
|
||||||
}
|
}
|
||||||
} else if (c == '{') {
|
}
|
||||||
|
else if (c == '{')
|
||||||
|
{
|
||||||
/* If we are staging a string, we must rotate here */
|
/* If we are staging a string, we must rotate here */
|
||||||
if (strings[0].ptr)
|
if (strings[0].ptr)
|
||||||
{
|
{
|
||||||
/* We have unacceptable tokens on this line */
|
/* We have unacceptable tokens on this line */
|
||||||
if (rotate(strings) != NULL)
|
if (rotate(strings) != NULL)
|
||||||
{
|
{
|
||||||
err = SMCParse_InvalidSection1;
|
err = SMCError_InvalidSection1;
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Sections must always be alone */
|
/* Sections must always be alone */
|
||||||
if (strings[2].ptr != NULL)
|
if (strings[2].ptr != NULL)
|
||||||
{
|
{
|
||||||
err = SMCParse_InvalidSection1;
|
err = SMCError_InvalidSection1;
|
||||||
goto failed;
|
goto failed;
|
||||||
} else if (strings[1].ptr == NULL) {
|
}
|
||||||
err = SMCParse_InvalidSection2;
|
else if (strings[1].ptr == NULL)
|
||||||
|
{
|
||||||
|
err = SMCError_InvalidSection2;
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
if ((res=smc->ReadSMC_NewSection(FixupString(strings[1]), strings[1].quoted))
|
if ((res=smc->ReadSMC_NewSection(&states, FixupString(strings[1])))
|
||||||
!= SMCParse_Continue)
|
!= SMCResult_Continue)
|
||||||
{
|
{
|
||||||
err = (res == SMCParse_HaltFail) ? SMCParse_Custom : SMCParse_Okay;
|
err = (res == SMCResult_HaltFail) ? SMCError_Custom : SMCError_Okay;
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
strings[1] = emptystring;
|
strings[1] = emptystring;
|
||||||
curlevel++;
|
curlevel++;
|
||||||
} else if (c == '}') {
|
}
|
||||||
|
else if (c == '}')
|
||||||
|
{
|
||||||
/* Unlike our matching friend, this can be on the same line as something prior */
|
/* Unlike our matching friend, this can be on the same line as something prior */
|
||||||
if (rotate(strings) != NULL)
|
if (rotate(strings) != NULL)
|
||||||
{
|
{
|
||||||
err = SMCParse_InvalidSection3;
|
err = SMCError_InvalidSection3;
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
if (strings[2].ptr)
|
if (strings[2].ptr)
|
||||||
{
|
{
|
||||||
if (!curlevel)
|
if (!curlevel)
|
||||||
{
|
{
|
||||||
err = SMCParse_InvalidProperty1;
|
err = SMCError_InvalidProperty1;
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
if ((res=smc->ReadSMC_KeyValue(
|
if ((res=smc->ReadSMC_KeyValue(
|
||||||
|
&states,
|
||||||
FixupString(strings[2]),
|
FixupString(strings[2]),
|
||||||
FixupString(strings[1]),
|
FixupString(strings[1])))
|
||||||
strings[2].quoted,
|
!= SMCResult_Continue)
|
||||||
strings[1].quoted))
|
|
||||||
!= SMCParse_Continue)
|
|
||||||
{
|
{
|
||||||
err = (res == SMCParse_HaltFail) ? SMCParse_Custom : SMCParse_Okay;
|
err = (res == SMCResult_HaltFail) ? SMCError_Custom : SMCError_Okay;
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
} else if (strings[1].ptr) {
|
}
|
||||||
err = SMCParse_InvalidSection3;
|
else if (strings[1].ptr)
|
||||||
|
{
|
||||||
|
err = SMCError_InvalidSection3;
|
||||||
goto failed;
|
goto failed;
|
||||||
} else if (!curlevel) {
|
}
|
||||||
err = SMCParse_InvalidSection4;
|
else if (!curlevel)
|
||||||
|
{
|
||||||
|
err = SMCError_InvalidSection4;
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
/* Now it's safe to leave the section */
|
/* Now it's safe to leave the section */
|
||||||
scrap(strings);
|
scrap(strings);
|
||||||
if ((res=smc->ReadSMC_LeavingSection()) != SMCParse_Continue)
|
if ((res=smc->ReadSMC_LeavingSection(&states)) != SMCResult_Continue)
|
||||||
{
|
{
|
||||||
err = (res == SMCParse_HaltFail) ? SMCParse_Custom : SMCParse_Okay;
|
err = (res == SMCResult_HaltFail) ? SMCError_Custom : SMCError_Okay;
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
curlevel--;
|
curlevel--;
|
||||||
} else if (c == '"') {
|
}
|
||||||
|
else if (c == '"')
|
||||||
|
{
|
||||||
/* If we get a quote mark, we always restage, but we need to do it beforehand */
|
/* If we get a quote mark, we always restage, but we need to do it beforehand */
|
||||||
if (strings[0].ptr)
|
if (strings[0].ptr)
|
||||||
{
|
{
|
||||||
strings[0].end = &parse_point[i];
|
strings[0].end = &parse_point[i];
|
||||||
if (rotate(strings) != NULL)
|
if (rotate(strings) != NULL)
|
||||||
{
|
{
|
||||||
err = SMCParse_InvalidTokens;
|
err = SMCError_InvalidTokens;
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
strings[0].ptr = &parse_point[i];
|
strings[0].ptr = &parse_point[i];
|
||||||
in_quote = true;
|
in_quote = true;
|
||||||
ignoring = true;
|
ignoring = true;
|
||||||
} else if (!strings[0].ptr) {
|
}
|
||||||
|
else if (!strings[0].ptr)
|
||||||
|
{
|
||||||
/* If we have no string, we must start one */
|
/* If we have no string, we must start one */
|
||||||
strings[0].ptr = &parse_point[i];
|
strings[0].ptr = &parse_point[i];
|
||||||
}
|
}
|
||||||
@ -574,11 +616,13 @@ SMCParseError TextParsers::ParseStream_SMC(void *stream,
|
|||||||
strings[0].end = &parse_point[i];
|
strings[0].end = &parse_point[i];
|
||||||
if (rotate(strings) != NULL)
|
if (rotate(strings) != NULL)
|
||||||
{
|
{
|
||||||
err = SMCParse_InvalidTokens;
|
err = SMCError_InvalidTokens;
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* If we're eating a string and get whitespace, we need to restage.
|
/* If we're eating a string and get whitespace, we need to restage.
|
||||||
* (Note that if we are quoted, this is being ignored)
|
* (Note that if we are quoted, this is being ignored)
|
||||||
*/
|
*/
|
||||||
@ -594,8 +638,10 @@ SMCParseError TextParsers::ParseStream_SMC(void *stream,
|
|||||||
/* There's no string, so we must move this one down and eat up another */
|
/* There's no string, so we must move this one down and eat up another */
|
||||||
strings[0].end = &parse_point[i];
|
strings[0].end = &parse_point[i];
|
||||||
rotate(strings);
|
rotate(strings);
|
||||||
} else if (!strings[1].quoted) {
|
}
|
||||||
err = SMCParse_InvalidTokens;
|
else if (!strings[1].quoted)
|
||||||
|
{
|
||||||
|
err = SMCError_InvalidTokens;
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -603,7 +649,7 @@ SMCParseError TextParsers::ParseStream_SMC(void *stream,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Advance which token we're on */
|
/* Advance which token we're on */
|
||||||
curtok++;
|
states.col++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (line_begin != in_buf)
|
if (line_begin != in_buf)
|
||||||
@ -637,8 +683,10 @@ SMCParseError TextParsers::ParseStream_SMC(void *stream,
|
|||||||
parse_point = &parse_point[read];
|
parse_point = &parse_point[read];
|
||||||
parse_point -= bytes;
|
parse_point -= bytes;
|
||||||
}
|
}
|
||||||
} else if (read == sizeof(in_buf) - 1) {
|
}
|
||||||
err = SMCParse_TokenOverflow;
|
else if (read == sizeof(in_buf) - 1)
|
||||||
|
{
|
||||||
|
err = SMCError_TokenOverflow;
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -646,29 +694,31 @@ SMCParseError TextParsers::ParseStream_SMC(void *stream,
|
|||||||
/* If we're done parsing and there are tokens left over... */
|
/* If we're done parsing and there are tokens left over... */
|
||||||
if (curlevel)
|
if (curlevel)
|
||||||
{
|
{
|
||||||
err = SMCParse_InvalidSection5;
|
err = SMCError_InvalidSection5;
|
||||||
goto failed;
|
goto failed;
|
||||||
} else if (strings[0].ptr || strings[1].ptr) {
|
}
|
||||||
err = SMCParse_InvalidTokens;
|
else if (strings[0].ptr || strings[1].ptr)
|
||||||
|
{
|
||||||
|
err = SMCError_InvalidTokens;
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
smc->ReadSMC_ParseEnd(false, false);
|
smc->ReadSMC_ParseEnd(false, false);
|
||||||
|
|
||||||
|
if (pStates != NULL)
|
||||||
|
{
|
||||||
|
*pStates = states;
|
||||||
|
}
|
||||||
|
|
||||||
return SMCParse_Okay;
|
return SMCError_Okay;
|
||||||
|
|
||||||
failed:
|
failed:
|
||||||
if (line)
|
if (pStates != NULL)
|
||||||
{
|
{
|
||||||
*line = curline;
|
*pStates = states;
|
||||||
}
|
}
|
||||||
|
|
||||||
smc->ReadSMC_ParseEnd(true, (err == SMCParse_Custom));
|
smc->ReadSMC_ParseEnd(true, (err == SMCError_Custom));
|
||||||
|
|
||||||
if (col)
|
|
||||||
{
|
|
||||||
*col = curtok;
|
|
||||||
}
|
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -976,7 +1026,7 @@ event_failed:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *TextParsers::GetSMCErrorString(SMCParseError err)
|
const char *TextParsers::GetSMCErrorString(SMCError err)
|
||||||
{
|
{
|
||||||
static const char *s_errors[] =
|
static const char *s_errors[] =
|
||||||
{
|
{
|
||||||
@ -994,7 +1044,7 @@ const char *TextParsers::GetSMCErrorString(SMCParseError err)
|
|||||||
"A property was declared outside of a section",
|
"A property was declared outside of a section",
|
||||||
};
|
};
|
||||||
|
|
||||||
if (err < SMCParse_Okay || err > SMCParse_InvalidProperty1)
|
if (err < SMCError_Okay || err > SMCError_InvalidProperty1)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -60,28 +60,26 @@ public:
|
|||||||
unsigned int *line,
|
unsigned int *line,
|
||||||
unsigned int *col);
|
unsigned int *col);
|
||||||
|
|
||||||
SMCParseError ParseFile_SMC(const char *file,
|
SMCError ParseFile_SMC(const char *file,
|
||||||
ITextListener_SMC *smc_listener,
|
ITextListener_SMC *smc_listener,
|
||||||
unsigned int *line,
|
SMCStates *states);
|
||||||
unsigned int *col);
|
|
||||||
|
|
||||||
unsigned int GetUTF8CharBytes(const char *stream);
|
unsigned int GetUTF8CharBytes(const char *stream);
|
||||||
|
|
||||||
const char *GetSMCErrorString(SMCParseError err);
|
const char *GetSMCErrorString(SMCError err);
|
||||||
bool IsWhitespace(const char *stream);
|
bool IsWhitespace(const char *stream);
|
||||||
private:
|
private:
|
||||||
SMCParseError ParseString_SMC(const char *stream,
|
SMCError ParseString_SMC(const char *stream,
|
||||||
ITextListener_SMC *smc,
|
ITextListener_SMC *smc,
|
||||||
unsigned int *line,
|
SMCStates *states);
|
||||||
unsigned int *col);
|
SMCError ParseStream_SMC(void *stream,
|
||||||
SMCParseError ParseStream_SMC(void *stream,
|
|
||||||
STREAMREADER srdr,
|
STREAMREADER srdr,
|
||||||
ITextListener_SMC *smc,
|
ITextListener_SMC *smc,
|
||||||
unsigned int *line,
|
SMCStates *states);
|
||||||
unsigned int *col);
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern TextParsers g_TextParser;
|
extern TextParsers g_TextParser;
|
||||||
|
|
||||||
#endif //_INCLUDE_SOURCEMOD_TEXTPARSERS_H_
|
#endif //_INCLUDE_SOURCEMOD_TEXTPARSERS_H_
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ void CPhraseFile::ReparseFile()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SMCParseError err;
|
SMCError err;
|
||||||
char path[PLATFORM_MAX_PATH];
|
char path[PLATFORM_MAX_PATH];
|
||||||
g_SourceMod.BuildPath(Path_SM, path, PLATFORM_MAX_PATH, "translations/%s", m_File.c_str());
|
g_SourceMod.BuildPath(Path_SM, path, PLATFORM_MAX_PATH, "translations/%s", m_File.c_str());
|
||||||
|
|
||||||
@ -137,9 +137,9 @@ void CPhraseFile::ReparseFile()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int line=0, col=0;
|
SMCStates states;
|
||||||
|
|
||||||
if ((err=textparsers->ParseFile_SMC(path, this, &line, &col)) != SMCParse_Okay)
|
if ((err=textparsers->ParseFile_SMC(path, this, &states)) != SMCError_Okay)
|
||||||
{
|
{
|
||||||
const char *msg = textparsers->GetSMCErrorString(err);
|
const char *msg = textparsers->GetSMCErrorString(err);
|
||||||
if (!msg)
|
if (!msg)
|
||||||
@ -148,7 +148,7 @@ void CPhraseFile::ReparseFile()
|
|||||||
}
|
}
|
||||||
|
|
||||||
g_Logger.LogError("[SM] Fatal error encountered parsing translation file \"%s\"", m_File.c_str());
|
g_Logger.LogError("[SM] Fatal error encountered parsing translation file \"%s\"", m_File.c_str());
|
||||||
g_Logger.LogError("[SM] Error (line %d, column %d): %s", line, col, msg);
|
g_Logger.LogError("[SM] Error (line %d, column %d): %s", states.line, states.col, msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,19 +156,11 @@ void CPhraseFile::ReadSMC_ParseStart()
|
|||||||
{
|
{
|
||||||
m_CurPhrase = -1;
|
m_CurPhrase = -1;
|
||||||
m_ParseState = PPS_None;
|
m_ParseState = PPS_None;
|
||||||
m_CurLine = 0;
|
|
||||||
m_FileLogged = false;
|
m_FileLogged = false;
|
||||||
m_LastPhraseString.clear();
|
m_LastPhraseString.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
SMCParseResult CPhraseFile::ReadSMC_RawLine(const char *line, unsigned int curline)
|
SMCResult CPhraseFile::ReadSMC_NewSection(const SMCStates *states, const char *name)
|
||||||
{
|
|
||||||
m_CurLine = curline;
|
|
||||||
|
|
||||||
return SMCParse_Continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
SMCParseResult CPhraseFile::ReadSMC_NewSection(const char *name, bool opt_quotes)
|
|
||||||
{
|
{
|
||||||
bool recognized = false;
|
bool recognized = false;
|
||||||
if (m_ParseState == PPS_None)
|
if (m_ParseState == PPS_None)
|
||||||
@ -178,7 +170,9 @@ SMCParseResult CPhraseFile::ReadSMC_NewSection(const char *name, bool opt_quotes
|
|||||||
m_ParseState = PPS_Phrases;
|
m_ParseState = PPS_Phrases;
|
||||||
recognized = true;
|
recognized = true;
|
||||||
}
|
}
|
||||||
} else if (m_ParseState == PPS_Phrases) {
|
}
|
||||||
|
else if (m_ParseState == PPS_Phrases)
|
||||||
|
{
|
||||||
m_ParseState = PPS_InPhrase;
|
m_ParseState = PPS_InPhrase;
|
||||||
recognized = true;
|
recognized = true;
|
||||||
|
|
||||||
@ -188,10 +182,12 @@ SMCParseResult CPhraseFile::ReadSMC_NewSection(const char *name, bool opt_quotes
|
|||||||
/* Create the reverse lookup */
|
/* Create the reverse lookup */
|
||||||
if (!sm_trie_insert(m_pPhraseLookup, name, reinterpret_cast<void *>(m_CurPhrase)))
|
if (!sm_trie_insert(m_pPhraseLookup, name, reinterpret_cast<void *>(m_CurPhrase)))
|
||||||
{
|
{
|
||||||
ParseWarning("Skipping duplicate phrase \"%s\" on line %d.", name, m_CurLine);
|
ParseWarning("Skipping duplicate phrase \"%s\" on line %d.", name, states->line);
|
||||||
/* :IDEA: prevent memory waste by seeking backwards in memtable? */
|
/* :IDEA: prevent memory waste by seeking backwards in memtable? */
|
||||||
m_CurPhrase = -1;
|
m_CurPhrase = -1;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* Initialize new phrase */
|
/* Initialize new phrase */
|
||||||
trans_t *pTrans;
|
trans_t *pTrans;
|
||||||
|
|
||||||
@ -211,25 +207,27 @@ SMCParseResult CPhraseFile::ReadSMC_NewSection(const char *name, bool opt_quotes
|
|||||||
}
|
}
|
||||||
m_LastPhraseString.assign(name);
|
m_LastPhraseString.assign(name);
|
||||||
}
|
}
|
||||||
} else if (m_ParseState == PPS_InPhrase) {
|
}
|
||||||
|
else if (m_ParseState == PPS_InPhrase)
|
||||||
|
{
|
||||||
ParseError("Phrase sections may not have sub-sections");
|
ParseError("Phrase sections may not have sub-sections");
|
||||||
return SMCParse_HaltFail;
|
return SMCResult_HaltFail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!recognized)
|
if (!recognized)
|
||||||
{
|
{
|
||||||
ParseWarning("Ignoring invalid section \"%s\" on line %d.", name, m_CurLine);
|
ParseWarning("Ignoring invalid section \"%s\" on line %d.", name, states->line);
|
||||||
}
|
}
|
||||||
|
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
SMCParseResult CPhraseFile::ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes)
|
SMCResult CPhraseFile::ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
|
||||||
{
|
{
|
||||||
/* See if we are ignoring a phrase */
|
/* See if we are ignoring a phrase */
|
||||||
if (m_CurPhrase == -1)
|
if (m_CurPhrase == -1)
|
||||||
{
|
{
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
phrase_t *pPhrase = (phrase_t *)m_pMemory->GetAddress(m_CurPhrase);
|
phrase_t *pPhrase = (phrase_t *)m_pMemory->GetAddress(m_CurPhrase);
|
||||||
@ -238,14 +236,14 @@ SMCParseResult CPhraseFile::ReadSMC_KeyValue(const char *key, const char *value,
|
|||||||
{
|
{
|
||||||
if (pPhrase->fmt_list != -1)
|
if (pPhrase->fmt_list != -1)
|
||||||
{
|
{
|
||||||
ParseWarning("Ignoring duplicated #format property on line %d", m_CurLine);
|
ParseWarning("Ignoring duplicated #format property on line %d", states->line);
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pPhrase->translations > 0)
|
if (pPhrase->translations > 0)
|
||||||
{
|
{
|
||||||
ParseWarning("#format property should come before translations on line %d, ignoring", m_CurLine);
|
ParseWarning("#format property should come before translations on line %d, ignoring", states->line);
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do an initial browsing for error checking and what not */
|
/* Do an initial browsing for error checking and what not */
|
||||||
@ -268,37 +266,47 @@ SMCParseResult CPhraseFile::ReadSMC_KeyValue(const char *key, const char *value,
|
|||||||
{
|
{
|
||||||
pPhrase->fmt_count++;
|
pPhrase->fmt_count++;
|
||||||
state = Parse_Index;
|
state = Parse_Index;
|
||||||
} else if (*value == ',') {
|
}
|
||||||
|
else if (*value == ',')
|
||||||
|
{
|
||||||
/* Do nothing */
|
/* Do nothing */
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
unsigned int bytes = textparsers->GetUTF8CharBytes(value);
|
unsigned int bytes = textparsers->GetUTF8CharBytes(value);
|
||||||
if (bytes != 1 || !isalpha(*value))
|
if (bytes != 1 || !isalpha(*value))
|
||||||
{
|
{
|
||||||
ParseWarning("Invalid token '%c' in #format property on line %d.", *value, m_CurLine);
|
ParseWarning("Invalid token '%c' in #format property on line %d.", *value, states->line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (state == Parse_Index) {
|
}
|
||||||
|
else if (state == Parse_Index)
|
||||||
|
{
|
||||||
if (*value == ':')
|
if (*value == ':')
|
||||||
{
|
{
|
||||||
state = Parse_Format;
|
state = Parse_Format;
|
||||||
if (value - last_value >= 15)
|
if (value - last_value >= 15)
|
||||||
{
|
{
|
||||||
ParseWarning("Too many digits in format index on line %d, phrase will be ignored.", m_CurLine);
|
ParseWarning("Too many digits in format index on line %d, phrase will be ignored.", states->line);
|
||||||
m_CurPhrase = -1;
|
m_CurPhrase = -1;
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
unsigned int bytes = textparsers->GetUTF8CharBytes(value);
|
unsigned int bytes = textparsers->GetUTF8CharBytes(value);
|
||||||
if (bytes != 1 || !isdigit(*value))
|
if (bytes != 1 || !isdigit(*value))
|
||||||
{
|
{
|
||||||
ParseWarning("Token '%c' in #format property on line %d is not a digit, phrase will be ignored.",
|
ParseWarning("Token '%c' in #format property on line %d is not a digit, phrase will be ignored.",
|
||||||
*value,
|
*value,
|
||||||
m_CurLine);
|
states->line);
|
||||||
m_CurPhrase = -1;
|
m_CurPhrase = -1;
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (state == Parse_Format) {
|
}
|
||||||
|
else if (state == Parse_Format)
|
||||||
|
{
|
||||||
if (*value == '}')
|
if (*value == '}')
|
||||||
{
|
{
|
||||||
state = Parse_None;
|
state = Parse_None;
|
||||||
@ -311,9 +319,9 @@ SMCParseResult CPhraseFile::ReadSMC_KeyValue(const char *key, const char *value,
|
|||||||
if (state != Parse_None)
|
if (state != Parse_None)
|
||||||
{
|
{
|
||||||
/* Moose clam cow. */
|
/* Moose clam cow. */
|
||||||
ParseWarning("Unterminated format string on line %d, phrase will be ignored.", m_CurLine);
|
ParseWarning("Unterminated format string on line %d, phrase will be ignored.", states->line);
|
||||||
m_CurPhrase = -1;
|
m_CurPhrase = -1;
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
value = old_value;
|
value = old_value;
|
||||||
|
|
||||||
@ -347,41 +355,49 @@ SMCParseResult CPhraseFile::ReadSMC_KeyValue(const char *key, const char *value,
|
|||||||
state = Parse_Index;
|
state = Parse_Index;
|
||||||
idx_ptr = NULL;
|
idx_ptr = NULL;
|
||||||
}
|
}
|
||||||
} else if (state == Parse_Index) {
|
}
|
||||||
|
else if (state == Parse_Index)
|
||||||
|
{
|
||||||
if (*in_ptr == ':')
|
if (*in_ptr == ':')
|
||||||
{
|
{
|
||||||
/* Check the number! */
|
/* Check the number! */
|
||||||
if (!idx_ptr)
|
if (!idx_ptr)
|
||||||
{
|
{
|
||||||
ParseWarning("Format property contains unindexed format string on line %d, phrase will be ignored.", m_CurLine);
|
ParseWarning("Format property contains unindexed format string on line %d, phrase will be ignored.", states->line);
|
||||||
m_CurPhrase = -1;
|
m_CurPhrase = -1;
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
long idx = strtol(idx_ptr, NULL, 10);
|
long idx = strtol(idx_ptr, NULL, 10);
|
||||||
if (idx < 1 || idx > (long)pPhrase->fmt_count)
|
if (idx < 1 || idx > (long)pPhrase->fmt_count)
|
||||||
{
|
{
|
||||||
ParseWarning("Format property contains invalid index '%d' on line %d, phrase will be ignored.", idx, m_CurLine);
|
ParseWarning("Format property contains invalid index '%d' on line %d, phrase will be ignored.", idx, states->line);
|
||||||
m_CurPhrase = -1;
|
m_CurPhrase = -1;
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
} else if (fmt_list[idx - 1] != -1) {
|
}
|
||||||
ParseWarning("Format property contains duplicated index '%d' on line %d, phrase will be ignored.", idx, m_CurLine);
|
else if (fmt_list[idx - 1] != -1)
|
||||||
|
{
|
||||||
|
ParseWarning("Format property contains duplicated index '%d' on line %d, phrase will be ignored.", idx, states->line);
|
||||||
m_CurPhrase = -1;
|
m_CurPhrase = -1;
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
cur_idx = (unsigned int)idx;
|
cur_idx = (unsigned int)idx;
|
||||||
state = Parse_Format;
|
state = Parse_Format;
|
||||||
out_ptr = NULL;
|
out_ptr = NULL;
|
||||||
} else if (!idx_ptr) {
|
}
|
||||||
|
else if (!idx_ptr)
|
||||||
|
{
|
||||||
idx_ptr = in_ptr;
|
idx_ptr = in_ptr;
|
||||||
}
|
}
|
||||||
} else if (state == Parse_Format) {
|
}
|
||||||
|
else if (state == Parse_Format)
|
||||||
|
{
|
||||||
if (*in_ptr == '}')
|
if (*in_ptr == '}')
|
||||||
{
|
{
|
||||||
if (!out_ptr)
|
if (!out_ptr)
|
||||||
{
|
{
|
||||||
ParseWarning("Format property contains empty format string on line %d, phrase will be ignored.", m_CurLine);
|
ParseWarning("Format property contains empty format string on line %d, phrase will be ignored.", states->line);
|
||||||
m_CurPhrase = -1;
|
m_CurPhrase = -1;
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
*out_ptr = '\0';
|
*out_ptr = '\0';
|
||||||
state = Parse_None;
|
state = Parse_None;
|
||||||
@ -392,7 +408,9 @@ SMCParseResult CPhraseFile::ReadSMC_KeyValue(const char *key, const char *value,
|
|||||||
pPhrase->fmt_bytes += strlen(fmt_buf);
|
pPhrase->fmt_bytes += strlen(fmt_buf);
|
||||||
fmt_list = (int *)m_pMemory->GetAddress(pPhrase->fmt_list);
|
fmt_list = (int *)m_pMemory->GetAddress(pPhrase->fmt_list);
|
||||||
fmt_list[cur_idx - 1] = tmp_idx;
|
fmt_list[cur_idx - 1] = tmp_idx;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (!out_ptr)
|
if (!out_ptr)
|
||||||
{
|
{
|
||||||
out_ptr = fmt_buf;
|
out_ptr = fmt_buf;
|
||||||
@ -402,9 +420,9 @@ SMCParseResult CPhraseFile::ReadSMC_KeyValue(const char *key, const char *value,
|
|||||||
if ((unsigned)(out_ptr - fmt_buf) >= sizeof(fmt_buf) - 1)
|
if ((unsigned)(out_ptr - fmt_buf) >= sizeof(fmt_buf) - 1)
|
||||||
{
|
{
|
||||||
ParseWarning("Format property contains format string that exceeds maximum length on line %d, phrase will be ignored.",
|
ParseWarning("Format property contains format string that exceeds maximum length on line %d, phrase will be ignored.",
|
||||||
m_CurLine);
|
states->line);
|
||||||
m_CurPhrase = -1;
|
m_CurPhrase = -1;
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
*out_ptr++ = *in_ptr;
|
*out_ptr++ = *in_ptr;
|
||||||
}
|
}
|
||||||
@ -421,17 +439,19 @@ SMCParseResult CPhraseFile::ReadSMC_KeyValue(const char *key, const char *value,
|
|||||||
{
|
{
|
||||||
ParseWarning("Format property contains no string for index %d on line %d, phrase will be ignored.",
|
ParseWarning("Format property contains no string for index %d on line %d, phrase will be ignored.",
|
||||||
i + 1,
|
i + 1,
|
||||||
m_CurLine);
|
states->line);
|
||||||
m_CurPhrase = -1;
|
m_CurPhrase = -1;
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
size_t len = strlen(key);
|
size_t len = strlen(key);
|
||||||
if (len != 2)
|
if (len != 2)
|
||||||
{
|
{
|
||||||
ParseWarning("Ignoring translation to invalid language \"%s\" on line %d.", key, m_CurLine);
|
ParseWarning("Ignoring translation to invalid language \"%s\" on line %d.", key, states->line);
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int lang;
|
unsigned int lang;
|
||||||
@ -440,7 +460,7 @@ SMCParseResult CPhraseFile::ReadSMC_KeyValue(const char *key, const char *value,
|
|||||||
/* Ignore if we don't have a language.
|
/* Ignore if we don't have a language.
|
||||||
* :IDEA: issue a one-time alert?
|
* :IDEA: issue a one-time alert?
|
||||||
*/
|
*/
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See how many bytes we need for this string, then allocate.
|
/* See how many bytes we need for this string, then allocate.
|
||||||
@ -515,7 +535,9 @@ SMCParseResult CPhraseFile::ReadSMC_KeyValue(const char *key, const char *value,
|
|||||||
}
|
}
|
||||||
/* Skip past the last byte read */
|
/* Skip past the last byte read */
|
||||||
in_ptr++;
|
in_ptr++;
|
||||||
} else if (*in_ptr == '{' && fmt_list != NULL) {
|
}
|
||||||
|
else if (*in_ptr == '{' && fmt_list != NULL)
|
||||||
|
{
|
||||||
/* Search for parameters if this is a formatted string */
|
/* Search for parameters if this is a formatted string */
|
||||||
const char *scrap_in_point = in_ptr;
|
const char *scrap_in_point = in_ptr;
|
||||||
const char *digit_start = ++in_ptr;
|
const char *digit_start = ++in_ptr;
|
||||||
@ -570,10 +592,10 @@ cont_loop:
|
|||||||
pPhrase->translations++;
|
pPhrase->translations++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
SMCParseResult CPhraseFile::ReadSMC_LeavingSection()
|
SMCResult CPhraseFile::ReadSMC_LeavingSection(const SMCStates *states)
|
||||||
{
|
{
|
||||||
if (m_ParseState == PPS_InPhrase)
|
if (m_ParseState == PPS_InPhrase)
|
||||||
{
|
{
|
||||||
@ -584,11 +606,13 @@ SMCParseResult CPhraseFile::ReadSMC_LeavingSection()
|
|||||||
m_CurPhrase = -1;
|
m_CurPhrase = -1;
|
||||||
m_ParseState = PPS_Phrases;
|
m_ParseState = PPS_Phrases;
|
||||||
m_LastPhraseString.assign("");
|
m_LastPhraseString.assign("");
|
||||||
} else if (m_ParseState == PPS_Phrases) {
|
}
|
||||||
|
else if (m_ParseState == PPS_Phrases)
|
||||||
|
{
|
||||||
m_ParseState = PPS_None;
|
m_ParseState = PPS_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPhraseFile::ReadSMC_ParseEnd(bool halted, bool failed)
|
void CPhraseFile::ReadSMC_ParseEnd(bool halted, bool failed)
|
||||||
@ -623,9 +647,8 @@ TransError CPhraseFile::GetTranslation(const char *szPhrase, unsigned int lang_i
|
|||||||
return Trans_BadPhraseLanguage;
|
return Trans_BadPhraseLanguage;
|
||||||
}
|
}
|
||||||
|
|
||||||
pTrans->fmt_order = (int *)m_pMemory->GetAddress(trans->fmt_order);
|
|
||||||
pTrans->fmt_count = pPhrase->fmt_count;
|
pTrans->fmt_count = pPhrase->fmt_count;
|
||||||
|
pTrans->fmt_order = pTrans->fmt_count > 0 ? (int *)m_pMemory->GetAddress(trans->fmt_order) : NULL;
|
||||||
pTrans->szPhrase = m_pStringTab->GetString(trans->stridx);
|
pTrans->szPhrase = m_pStringTab->GetString(trans->stridx);
|
||||||
|
|
||||||
return Trans_Okay;
|
return Trans_Okay;
|
||||||
@ -811,9 +834,9 @@ void Translator::RebuildLanguageDatabase(const char *lang_header_file)
|
|||||||
m_Languages.clear();
|
m_Languages.clear();
|
||||||
|
|
||||||
/* Start anew */
|
/* Start anew */
|
||||||
SMCParseError err;
|
SMCError err;
|
||||||
unsigned int line=0, col=0;
|
SMCStates states;
|
||||||
if ((err=textparsers->ParseFile_SMC(lang_header_file, this, &line, &col)) != SMCParse_Okay)
|
if ((err=textparsers->ParseFile_SMC(lang_header_file, this, &states)) != SMCError_Okay)
|
||||||
{
|
{
|
||||||
const char *str_err = textparsers->GetSMCErrorString(err);
|
const char *str_err = textparsers->GetSMCErrorString(err);
|
||||||
if (!str_err)
|
if (!str_err)
|
||||||
@ -822,7 +845,7 @@ void Translator::RebuildLanguageDatabase(const char *lang_header_file)
|
|||||||
}
|
}
|
||||||
|
|
||||||
g_Logger.LogError("[SM] Failed to parse language header file: \"%s\"", lang_header_file);
|
g_Logger.LogError("[SM] Failed to parse language header file: \"%s\"", lang_header_file);
|
||||||
g_Logger.LogError("[SM] Parse error (line %d, column %d): %s", line, col, str_err);
|
g_Logger.LogError("[SM] Parse error (line %d, column %d): %s", states.line, states.col, str_err);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *serverLang;
|
void *serverLang;
|
||||||
@ -854,7 +877,7 @@ void Translator::ReadSMC_ParseStart()
|
|||||||
m_CustomError.clear();
|
m_CustomError.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
SMCParseResult Translator::ReadSMC_NewSection(const char *name, bool opt_quotes)
|
SMCResult Translator::ReadSMC_NewSection(const SMCStates *states, const char *name)
|
||||||
{
|
{
|
||||||
if (!m_InLanguageSection)
|
if (!m_InLanguageSection)
|
||||||
{
|
{
|
||||||
@ -869,17 +892,17 @@ SMCParseResult Translator::ReadSMC_NewSection(const char *name, bool opt_quotes)
|
|||||||
g_Logger.LogError("[SM] Warning: Unrecognized section \"%s\" in languages.cfg", name);
|
g_Logger.LogError("[SM] Warning: Unrecognized section \"%s\" in languages.cfg", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
SMCParseResult Translator::ReadSMC_LeavingSection()
|
SMCResult Translator::ReadSMC_LeavingSection(const SMCStates *states)
|
||||||
{
|
{
|
||||||
m_InLanguageSection = false;
|
m_InLanguageSection = false;
|
||||||
|
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
SMCParseResult Translator::ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes)
|
SMCResult Translator::ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
|
||||||
{
|
{
|
||||||
size_t len = strlen(key);
|
size_t len = strlen(key);
|
||||||
|
|
||||||
@ -891,7 +914,7 @@ SMCParseResult Translator::ReadSMC_KeyValue(const char *key, const char *value,
|
|||||||
|
|
||||||
AddLanguage(key, value);
|
AddLanguage(key, value);
|
||||||
|
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Translator::AddLanguage(const char *langcode, const char *description)
|
bool Translator::AddLanguage(const char *langcode, const char *description)
|
||||||
|
@ -89,11 +89,10 @@ public:
|
|||||||
TransError GetTranslation(const char *szPhrase, unsigned int lang_id, Translation *pTrans);
|
TransError GetTranslation(const char *szPhrase, unsigned int lang_id, Translation *pTrans);
|
||||||
public: //ITextListener_SMC
|
public: //ITextListener_SMC
|
||||||
void ReadSMC_ParseStart();
|
void ReadSMC_ParseStart();
|
||||||
|
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
|
||||||
|
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
|
||||||
|
SMCResult ReadSMC_LeavingSection(const SMCStates *states);
|
||||||
void ReadSMC_ParseEnd(bool halted, bool failed);
|
void ReadSMC_ParseEnd(bool halted, bool failed);
|
||||||
SMCParseResult ReadSMC_NewSection(const char *name, bool opt_quotes);
|
|
||||||
SMCParseResult ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes);
|
|
||||||
SMCParseResult ReadSMC_LeavingSection();
|
|
||||||
SMCParseResult ReadSMC_RawLine(const char *line, unsigned int curline);
|
|
||||||
private:
|
private:
|
||||||
void ParseError(const char *message, ...);
|
void ParseError(const char *message, ...);
|
||||||
void ParseWarning(const char *message, ...);
|
void ParseWarning(const char *message, ...);
|
||||||
@ -108,7 +107,6 @@ private:
|
|||||||
unsigned int m_LangCount;
|
unsigned int m_LangCount;
|
||||||
String m_ParseError;
|
String m_ParseError;
|
||||||
String m_LastPhraseString;
|
String m_LastPhraseString;
|
||||||
unsigned int m_CurLine;
|
|
||||||
bool m_FileLogged;
|
bool m_FileLogged;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -129,9 +127,9 @@ public: // SMGlobalClass
|
|||||||
void OnSourceModLevelChange(const char *mapName);
|
void OnSourceModLevelChange(const char *mapName);
|
||||||
public: // ITextListener_SMC
|
public: // ITextListener_SMC
|
||||||
void ReadSMC_ParseStart();
|
void ReadSMC_ParseStart();
|
||||||
SMCParseResult ReadSMC_NewSection(const char *name, bool opt_quotes);
|
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
|
||||||
SMCParseResult ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes);
|
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
|
||||||
SMCParseResult ReadSMC_LeavingSection();
|
SMCResult ReadSMC_LeavingSection(const SMCStates *states);
|
||||||
public:
|
public:
|
||||||
void RebuildLanguageDatabase(const char *lang_header_file);
|
void RebuildLanguageDatabase(const char *lang_header_file);
|
||||||
unsigned int FindOrAddPhraseFile(const char *phrase_file);
|
unsigned int FindOrAddPhraseFile(const char *phrase_file);
|
||||||
|
@ -71,41 +71,41 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SMCParseResult ReadSMC_NewSection(const char *name, bool opt_quotes)
|
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name)
|
||||||
{
|
{
|
||||||
cell_t result = SMCParse_Continue;
|
cell_t result = SMCResult_Continue;
|
||||||
|
|
||||||
if (new_section)
|
if (new_section)
|
||||||
{
|
{
|
||||||
new_section->PushCell(handle);
|
new_section->PushCell(handle);
|
||||||
new_section->PushString(name);
|
new_section->PushString(name);
|
||||||
new_section->PushCell(opt_quotes ? 1 : 0);
|
new_section->PushCell(1);
|
||||||
new_section->Execute(&result);
|
new_section->Execute(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (SMCParseResult)result;
|
return (SMCResult)result;
|
||||||
}
|
}
|
||||||
|
|
||||||
SMCParseResult ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes)
|
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
|
||||||
{
|
{
|
||||||
cell_t result = SMCParse_Continue;
|
cell_t result = SMCResult_Continue;
|
||||||
|
|
||||||
if (key_value)
|
if (key_value)
|
||||||
{
|
{
|
||||||
key_value->PushCell(handle);
|
key_value->PushCell(handle);
|
||||||
key_value->PushString(key);
|
key_value->PushString(key);
|
||||||
key_value->PushString(value);
|
key_value->PushString(value);
|
||||||
key_value->PushCell(key_quotes ? 1 : 0);
|
key_value->PushCell(1);
|
||||||
key_value->PushCell(value_quotes ? 1 : 0);
|
key_value->PushCell(1);
|
||||||
key_value->Execute(&result);
|
key_value->Execute(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (SMCParseResult)result;
|
return (SMCResult)result;
|
||||||
}
|
}
|
||||||
|
|
||||||
SMCParseResult ReadSMC_LeavingSection()
|
SMCResult ReadSMC_LeavingSection(const SMCStates *states)
|
||||||
{
|
{
|
||||||
cell_t result = SMCParse_Continue;
|
cell_t result = SMCResult_Continue;
|
||||||
|
|
||||||
if (end_section)
|
if (end_section)
|
||||||
{
|
{
|
||||||
@ -113,22 +113,22 @@ public:
|
|||||||
end_section->Execute(&result);
|
end_section->Execute(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (SMCParseResult)result;
|
return (SMCResult)result;
|
||||||
}
|
}
|
||||||
|
|
||||||
SMCParseResult ReadSMC_RawLine(const char *line, unsigned int curline)
|
SMCResult ReadSMC_RawLine(const SMCStates *states, const char *line)
|
||||||
{
|
{
|
||||||
cell_t result = SMCParse_Continue;
|
cell_t result = SMCResult_Continue;
|
||||||
|
|
||||||
if (raw_line)
|
if (raw_line)
|
||||||
{
|
{
|
||||||
raw_line->PushCell(handle);
|
raw_line->PushCell(handle);
|
||||||
raw_line->PushString(line);
|
raw_line->PushString(line);
|
||||||
raw_line->PushCell(curline);
|
raw_line->PushCell(states->line);
|
||||||
raw_line->Execute(&result);
|
raw_line->Execute(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (SMCParseResult)result;
|
return (SMCResult)result;
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
IPluginFunction *parse_start;
|
IPluginFunction *parse_start;
|
||||||
@ -279,22 +279,22 @@ static cell_t SMC_ParseFile(IPluginContext *pContext, const cell_t *params)
|
|||||||
char path[PLATFORM_MAX_PATH];
|
char path[PLATFORM_MAX_PATH];
|
||||||
g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "%s", file);
|
g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "%s", file);
|
||||||
|
|
||||||
unsigned int line = 0, col = 0;
|
SMCStates states;
|
||||||
SMCParseError p_err = textparsers->ParseFile_SMC(path, parse, &line, &col);
|
SMCError p_err = textparsers->ParseFile_SMC(path, parse, &states);
|
||||||
|
|
||||||
cell_t *c_line, *c_col;
|
cell_t *c_line, *c_col;
|
||||||
pContext->LocalToPhysAddr(params[3], &c_line);
|
pContext->LocalToPhysAddr(params[3], &c_line);
|
||||||
pContext->LocalToPhysAddr(params[4], &c_col);
|
pContext->LocalToPhysAddr(params[4], &c_col);
|
||||||
|
|
||||||
*c_line = line;
|
*c_line = states.line;
|
||||||
*c_col = col;
|
*c_col = states.col;
|
||||||
|
|
||||||
return (cell_t)p_err;
|
return (cell_t)p_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static cell_t SMC_GetErrorString(IPluginContext *pContext, const cell_t *params)
|
static cell_t SMC_GetErrorString(IPluginContext *pContext, const cell_t *params)
|
||||||
{
|
{
|
||||||
const char *str = textparsers->GetSMCErrorString((SMCParseError)params[1]);
|
const char *str = textparsers->GetSMCErrorString((SMCError)params[1]);
|
||||||
|
|
||||||
if (!str)
|
if (!str)
|
||||||
{
|
{
|
||||||
|
@ -82,7 +82,7 @@ void CPluginInfoDatabase::ReadSMC_ParseStart()
|
|||||||
m_infodb = -1;
|
m_infodb = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
SMCParseResult CPluginInfoDatabase::MakeError(const char *fmt, ...)
|
SMCResult CPluginInfoDatabase::MakeError(const char *fmt, ...)
|
||||||
{
|
{
|
||||||
char buffer[512];
|
char buffer[512];
|
||||||
va_list ap;
|
va_list ap;
|
||||||
@ -93,7 +93,7 @@ SMCParseResult CPluginInfoDatabase::MakeError(const char *fmt, ...)
|
|||||||
|
|
||||||
m_errmsg = m_strtab->AddString(buffer);
|
m_errmsg = m_strtab->AddString(buffer);
|
||||||
|
|
||||||
return SMCParse_HaltFail;
|
return SMCResult_HaltFail;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int CPluginInfoDatabase::GetSettingsNum()
|
unsigned int CPluginInfoDatabase::GetSettingsNum()
|
||||||
@ -149,10 +149,7 @@ void CPluginInfoDatabase::GetOptionsForPlugin(PluginSettings *settings, unsigned
|
|||||||
*val = m_strtab->GetString(table[opt_num].val);
|
*val = m_strtab->GetString(table[opt_num].val);
|
||||||
}
|
}
|
||||||
|
|
||||||
SMCParseResult CPluginInfoDatabase::ReadSMC_KeyValue(const char *key,
|
SMCResult CPluginInfoDatabase::ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
|
||||||
const char *value,
|
|
||||||
bool key_quotes,
|
|
||||||
bool value_quotes)
|
|
||||||
{
|
{
|
||||||
if (cur_plugin != -1)
|
if (cur_plugin != -1)
|
||||||
{
|
{
|
||||||
@ -164,28 +161,46 @@ SMCParseResult CPluginInfoDatabase::ReadSMC_KeyValue(const char *key,
|
|||||||
if (strcasecmp(value, "yes") == 0)
|
if (strcasecmp(value, "yes") == 0)
|
||||||
{
|
{
|
||||||
plugin->pause_val = true;
|
plugin->pause_val = true;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
plugin->pause_val = false;
|
plugin->pause_val = false;
|
||||||
}
|
}
|
||||||
} else if (strcmp(key, "lifetime") == 0) {
|
}
|
||||||
|
else if (strcmp(key, "lifetime") == 0)
|
||||||
|
{
|
||||||
if (strcasecmp(value, "private") == 0)
|
if (strcasecmp(value, "private") == 0)
|
||||||
{
|
{
|
||||||
plugin->type_val = PluginType_Private;
|
plugin->type_val = PluginType_Private;
|
||||||
} else if (strcasecmp(value, "mapsync") == 0) {
|
}
|
||||||
|
else if (strcasecmp(value, "mapsync") == 0)
|
||||||
|
{
|
||||||
plugin->type_val = PluginType_MapUpdated;
|
plugin->type_val = PluginType_MapUpdated;
|
||||||
} else if (strcasecmp(value, "maponly") == 0) {
|
}
|
||||||
|
else if (strcasecmp(value, "maponly") == 0)
|
||||||
|
{
|
||||||
plugin->type_val = PluginType_MapOnly;
|
plugin->type_val = PluginType_MapOnly;
|
||||||
} else if (strcasecmp(value, "global") == 0) {
|
}
|
||||||
|
else if (strcasecmp(value, "global") == 0)
|
||||||
|
{
|
||||||
plugin->type_val = PluginType_Global;
|
plugin->type_val = PluginType_Global;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return MakeError("Unknown value for key \"lifetime\": \"%s\"", value);
|
return MakeError("Unknown value for key \"lifetime\": \"%s\"", value);
|
||||||
}
|
}
|
||||||
} else if (strcmp(key, "blockload") == 0) {
|
}
|
||||||
|
else if (strcmp(key, "blockload") == 0)
|
||||||
|
{
|
||||||
plugin->blockload_val = true;
|
plugin->blockload_val = true;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return MakeError("Unknown property key: \"%s\"", key);
|
return MakeError("Unknown property key: \"%s\"", key);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* Cache every option, valid or not */
|
/* Cache every option, valid or not */
|
||||||
int keyidx = m_strtab->AddString(key);
|
int keyidx = m_strtab->AddString(key);
|
||||||
int validx = m_strtab->AddString(value);
|
int validx = m_strtab->AddString(value);
|
||||||
@ -199,7 +214,9 @@ SMCParseResult CPluginInfoDatabase::ReadSMC_KeyValue(const char *key,
|
|||||||
{
|
{
|
||||||
//right now we don't have many
|
//right now we don't have many
|
||||||
plugin->opts_size = 2;
|
plugin->opts_size = 2;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
plugin->opts_size *= 2;
|
plugin->opts_size *= 2;
|
||||||
}
|
}
|
||||||
int newidx = memtab->CreateMem(plugin->opts_size * sizeof(PluginOpts), (void **)&table);
|
int newidx = memtab->CreateMem(plugin->opts_size * sizeof(PluginOpts), (void **)&table);
|
||||||
@ -211,23 +228,29 @@ SMCParseResult CPluginInfoDatabase::ReadSMC_KeyValue(const char *key,
|
|||||||
memcpy(table, oldtable, oldsize * sizeof(PluginOpts));
|
memcpy(table, oldtable, oldsize * sizeof(PluginOpts));
|
||||||
}
|
}
|
||||||
plugin->optarray = newidx;
|
plugin->optarray = newidx;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
table = (PluginOpts *)memtab->GetAddress(plugin->optarray);
|
table = (PluginOpts *)memtab->GetAddress(plugin->optarray);
|
||||||
}
|
}
|
||||||
PluginOpts *opt = &table[plugin->opts_num++];
|
PluginOpts *opt = &table[plugin->opts_num++];
|
||||||
opt->key = keyidx;
|
opt->key = keyidx;
|
||||||
opt->val = validx;
|
opt->val = validx;
|
||||||
}
|
}
|
||||||
} else if (in_plugins) {
|
}
|
||||||
|
else if (in_plugins)
|
||||||
|
{
|
||||||
return MakeError("Unknown property key: \"%s\"", key);
|
return MakeError("Unknown property key: \"%s\"", key);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* Ignore anything we don't know about! */
|
/* Ignore anything we don't know about! */
|
||||||
}
|
}
|
||||||
|
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
SMCParseResult CPluginInfoDatabase::ReadSMC_LeavingSection()
|
SMCResult CPluginInfoDatabase::ReadSMC_LeavingSection(const SMCStates *states)
|
||||||
{
|
{
|
||||||
if (in_plugins)
|
if (in_plugins)
|
||||||
{
|
{
|
||||||
@ -236,7 +259,9 @@ SMCParseResult CPluginInfoDatabase::ReadSMC_LeavingSection()
|
|||||||
if (in_options)
|
if (in_options)
|
||||||
{
|
{
|
||||||
in_options = false;
|
in_options = false;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* If the plugin is ending, add it to the table */
|
/* If the plugin is ending, add it to the table */
|
||||||
BaseMemTable *memtab = m_strtab->GetMemTable();
|
BaseMemTable *memtab = m_strtab->GetMemTable();
|
||||||
int *table;
|
int *table;
|
||||||
@ -246,7 +271,9 @@ SMCParseResult CPluginInfoDatabase::ReadSMC_LeavingSection()
|
|||||||
if (!m_infodb_size)
|
if (!m_infodb_size)
|
||||||
{
|
{
|
||||||
m_infodb_size = 8;
|
m_infodb_size = 8;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
m_infodb_size *= 2;
|
m_infodb_size *= 2;
|
||||||
}
|
}
|
||||||
int newidx = memtab->CreateMem(m_infodb_size, (void **)&table);
|
int newidx = memtab->CreateMem(m_infodb_size, (void **)&table);
|
||||||
@ -256,22 +283,26 @@ SMCParseResult CPluginInfoDatabase::ReadSMC_LeavingSection()
|
|||||||
memcpy(table, oldtable, oldsize * sizeof(int));
|
memcpy(table, oldtable, oldsize * sizeof(int));
|
||||||
}
|
}
|
||||||
m_infodb = newidx;
|
m_infodb = newidx;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
table = (int *)memtab->GetAddress(m_infodb);
|
table = (int *)memtab->GetAddress(m_infodb);
|
||||||
}
|
}
|
||||||
/* Assign to table and scrap the current plugin */
|
/* Assign to table and scrap the current plugin */
|
||||||
table[m_infodb_count++] = cur_plugin;
|
table[m_infodb_count++] = cur_plugin;
|
||||||
cur_plugin = -1;
|
cur_plugin = -1;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
in_plugins = false;
|
in_plugins = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
SMCParseResult CPluginInfoDatabase::ReadSMC_NewSection(const char *name, bool opt_quotes)
|
SMCResult CPluginInfoDatabase::ReadSMC_NewSection(const SMCStates *states, const char *name)
|
||||||
{
|
{
|
||||||
if (!in_plugins)
|
if (!in_plugins)
|
||||||
{
|
{
|
||||||
@ -279,13 +310,17 @@ SMCParseResult CPluginInfoDatabase::ReadSMC_NewSection(const char *name, bool op
|
|||||||
if (strcmp(name, "Plugins") != 0)
|
if (strcmp(name, "Plugins") != 0)
|
||||||
{
|
{
|
||||||
return MakeError("Unknown root section: \"%s\"", name);
|
return MakeError("Unknown root section: \"%s\"", name);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* Otherwise set our states */
|
/* Otherwise set our states */
|
||||||
in_plugins = true;
|
in_plugins = true;
|
||||||
cur_plugin = -1;
|
cur_plugin = -1;
|
||||||
in_options = false;
|
in_options = false;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (cur_plugin == -1)
|
if (cur_plugin == -1)
|
||||||
{
|
{
|
||||||
/* If we get a plugin node and we don't have a current plugin, create a new one */
|
/* If we get a plugin node and we don't have a current plugin, create a new one */
|
||||||
@ -295,15 +330,20 @@ SMCParseResult CPluginInfoDatabase::ReadSMC_NewSection(const char *name, bool op
|
|||||||
plugin->Init();
|
plugin->Init();
|
||||||
plugin->name = i_name;
|
plugin->name = i_name;
|
||||||
in_options = false;
|
in_options = false;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (!in_options && strcmp(name, "Options") == 0)
|
if (!in_options && strcmp(name, "Options") == 0)
|
||||||
{
|
{
|
||||||
in_options = true;
|
in_options = true;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return MakeError("Unknown plugin sub-section: \"%s\"", name);
|
return MakeError("Unknown plugin sub-section: \"%s\"", name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,9 +68,9 @@ public:
|
|||||||
~CPluginInfoDatabase();
|
~CPluginInfoDatabase();
|
||||||
public: //ITextListener_SMC
|
public: //ITextListener_SMC
|
||||||
void ReadSMC_ParseStart();
|
void ReadSMC_ParseStart();
|
||||||
SMCParseResult ReadSMC_NewSection(const char *name, bool opt_quotes);
|
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
|
||||||
SMCParseResult ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes);
|
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
|
||||||
SMCParseResult ReadSMC_LeavingSection();
|
SMCResult ReadSMC_LeavingSection(const SMCStates *states);
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Returns the number of plugin settings available.
|
* Returns the number of plugin settings available.
|
||||||
@ -90,7 +90,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
void GetOptionsForPlugin(PluginSettings *settings, unsigned int opt_num, const char **key, const char **val);
|
void GetOptionsForPlugin(PluginSettings *settings, unsigned int opt_num, const char **key, const char **val);
|
||||||
private:
|
private:
|
||||||
SMCParseResult MakeError(const char *fmt, ...);
|
SMCResult MakeError(const char *fmt, ...);
|
||||||
private:
|
private:
|
||||||
BaseStringTable *m_strtab;
|
BaseStringTable *m_strtab;
|
||||||
int m_errmsg;
|
int m_errmsg;
|
||||||
|
@ -819,10 +819,10 @@ void CPluginManager::Shutdown()
|
|||||||
void CPluginManager::LoadAll_FirstPass(const char *config, const char *basedir)
|
void CPluginManager::LoadAll_FirstPass(const char *config, const char *basedir)
|
||||||
{
|
{
|
||||||
/* First read in the database of plugin settings */
|
/* First read in the database of plugin settings */
|
||||||
SMCParseError err;
|
SMCError err;
|
||||||
unsigned int line, col;
|
SMCStates states;
|
||||||
m_AllPluginsLoaded = false;
|
m_AllPluginsLoaded = false;
|
||||||
if ((err=textparsers->ParseFile_SMC(config, &m_PluginInfo, &line, &col)) != SMCParse_Okay)
|
if ((err=textparsers->ParseFile_SMC(config, &m_PluginInfo, &states)) != SMCError_Okay)
|
||||||
{
|
{
|
||||||
g_Logger.LogError("[SM] Encountered fatal error parsing file \"%s\"", config);
|
g_Logger.LogError("[SM] Encountered fatal error parsing file \"%s\"", config);
|
||||||
const char *err_msg = textparsers->GetSMCErrorString(err);
|
const char *err_msg = textparsers->GetSMCErrorString(err);
|
||||||
|
@ -811,7 +811,7 @@ int BaseContext::StringToLocal(cell_t local_addr, size_t bytes, const char *sour
|
|||||||
len = bytes - 1;
|
len = bytes - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(dest, source, len);
|
memmove(dest, source, len);
|
||||||
dest[len] = '\0';
|
dest[len] = '\0';
|
||||||
|
|
||||||
return SP_ERROR_NONE;
|
return SP_ERROR_NONE;
|
||||||
@ -880,7 +880,7 @@ int BaseContext::StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const cha
|
|||||||
needtocheck = true;
|
needtocheck = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(dest, source, len);
|
memmove(dest, source, len);
|
||||||
if ((dest[len-1] & 1<<7) && needtocheck)
|
if ((dest[len-1] & 1<<7) && needtocheck)
|
||||||
{
|
{
|
||||||
len -= __CheckValidChar(dest+len-1);
|
len -= __CheckValidChar(dest+len-1);
|
||||||
|
@ -895,11 +895,11 @@ void TopMenu::TearDownClient(topmenu_player_t *player)
|
|||||||
|
|
||||||
bool TopMenu::LoadConfiguration(const char *file, char *error, size_t maxlength)
|
bool TopMenu::LoadConfiguration(const char *file, char *error, size_t maxlength)
|
||||||
{
|
{
|
||||||
SMCParseError err;
|
SMCError err;
|
||||||
unsigned int line = 0, col = 0;
|
SMCStates states;
|
||||||
|
|
||||||
if ((err = textparsers->ParseFile_SMC(file, this, &line, &col))
|
if ((err = textparsers->ParseFile_SMC(file, this, &states))
|
||||||
!= SMCParse_Okay)
|
!= SMCError_Okay)
|
||||||
{
|
{
|
||||||
const char *err_string = textparsers->GetSMCErrorString(err);
|
const char *err_string = textparsers->GetSMCErrorString(err);
|
||||||
if (!err_string)
|
if (!err_string)
|
||||||
@ -971,7 +971,7 @@ void TopMenu::ReadSMC_ParseStart()
|
|||||||
m_Config.cats.clear();
|
m_Config.cats.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
SMCParseResult TopMenu::ReadSMC_NewSection(const char *name, bool opt_quotes)
|
SMCResult TopMenu::ReadSMC_NewSection(const SMCStates *states, const char *name)
|
||||||
{
|
{
|
||||||
if (ignore_parse_level)
|
if (ignore_parse_level)
|
||||||
{
|
{
|
||||||
@ -1003,16 +1003,16 @@ SMCParseResult TopMenu::ReadSMC_NewSection(const char *name, bool opt_quotes)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
SMCParseResult TopMenu::ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes)
|
SMCResult TopMenu::ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
|
||||||
{
|
{
|
||||||
if (ignore_parse_level > 0
|
if (ignore_parse_level > 0
|
||||||
|| current_parse_state != PARSE_STATE_CATEGORY
|
|| current_parse_state != PARSE_STATE_CATEGORY
|
||||||
|| cur_cat == NULL)
|
|| cur_cat == NULL)
|
||||||
{
|
{
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(key, "item") == 0)
|
if (strcmp(key, "item") == 0)
|
||||||
@ -1020,10 +1020,10 @@ SMCParseResult TopMenu::ReadSMC_KeyValue(const char *key, const char *value, boo
|
|||||||
cur_cat->commands.push_back(m_Config.strings.AddString(value));
|
cur_cat->commands.push_back(m_Config.strings.AddString(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
SMCParseResult TopMenu::ReadSMC_LeavingSection()
|
SMCResult TopMenu::ReadSMC_LeavingSection(const SMCStates *states)
|
||||||
{
|
{
|
||||||
if (ignore_parse_level)
|
if (ignore_parse_level)
|
||||||
{
|
{
|
||||||
@ -1042,7 +1042,7 @@ SMCParseResult TopMenu::ReadSMC_LeavingSection()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int TopMenu::FindCategory(const char *name)
|
unsigned int TopMenu::FindCategory(const char *name)
|
||||||
|
@ -141,13 +141,10 @@ public: //IMenuHandler
|
|||||||
const ItemDrawInfo &dr);
|
const ItemDrawInfo &dr);
|
||||||
virtual void OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason);
|
virtual void OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason);
|
||||||
public: //ITextListener_SMC
|
public: //ITextListener_SMC
|
||||||
virtual void ReadSMC_ParseStart();
|
void ReadSMC_ParseStart();
|
||||||
SMCParseResult ReadSMC_NewSection(const char *name, bool opt_quotes);
|
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
|
||||||
SMCParseResult ReadSMC_KeyValue(const char *key,
|
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
|
||||||
const char *value,
|
SMCResult ReadSMC_LeavingSection(const SMCStates *states);
|
||||||
bool key_quotes,
|
|
||||||
bool value_quotes);
|
|
||||||
SMCParseResult ReadSMC_LeavingSection();
|
|
||||||
private:
|
private:
|
||||||
void SortCategoriesIfNeeded();
|
void SortCategoriesIfNeeded();
|
||||||
void SortCategoryIfNeeded(unsigned int category);
|
void SortCategoryIfNeeded(unsigned int category);
|
||||||
|
@ -41,6 +41,10 @@
|
|||||||
|
|
||||||
namespace SourceMod
|
namespace SourceMod
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#define SMINTERFACE_TEXTPARSERS_NAME "ITextParsers"
|
||||||
|
#define SMINTERFACE_TEXTPARSERS_VERSION 2
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The INI file format is defined as:
|
* The INI file format is defined as:
|
||||||
* WHITESPACE: 0x20, \n, \t, \r
|
* WHITESPACE: 0x20, \n, \t, \r
|
||||||
@ -85,6 +89,14 @@ namespace SourceMod
|
|||||||
*/
|
*/
|
||||||
class ITextListener_INI
|
class ITextListener_INI
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Returns version number.
|
||||||
|
*/
|
||||||
|
virtual unsigned int GetTextParserVersion1()
|
||||||
|
{
|
||||||
|
return SMINTERFACE_TEXTPARSERS_VERSION;
|
||||||
|
}
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Called when a new section is encountered in an INI file.
|
* @brief Called when a new section is encountered in an INI file.
|
||||||
@ -183,30 +195,39 @@ namespace SourceMod
|
|||||||
/**
|
/**
|
||||||
* @brief Lists actions to take when an SMC parse hook is done.
|
* @brief Lists actions to take when an SMC parse hook is done.
|
||||||
*/
|
*/
|
||||||
enum SMCParseResult
|
enum SMCResult
|
||||||
{
|
{
|
||||||
SMCParse_Continue, /**< Continue parsing */
|
SMCResult_Continue, /**< Continue parsing */
|
||||||
SMCParse_Halt, /**< Stop parsing here */
|
SMCResult_Halt, /**< Stop parsing here */
|
||||||
SMCParse_HaltFail /**< Stop parsing and return SMCParseError_Custom */
|
SMCResult_HaltFail /**< Stop parsing and return SMCError_Custom */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Lists error codes possible from parsing an SMC file.
|
* @brief Lists error codes possible from parsing an SMC file.
|
||||||
*/
|
*/
|
||||||
enum SMCParseError
|
enum SMCError
|
||||||
{
|
{
|
||||||
SMCParse_Okay = 0, /**< No error */
|
SMCError_Okay = 0, /**< No error */
|
||||||
SMCParse_StreamOpen, /**< Stream failed to open */
|
SMCError_StreamOpen, /**< Stream failed to open */
|
||||||
SMCParse_StreamError, /**< The stream died... somehow */
|
SMCError_StreamError, /**< The stream died... somehow */
|
||||||
SMCParse_Custom, /**< A custom handler threw an error */
|
SMCError_Custom, /**< A custom handler threw an error */
|
||||||
SMCParse_InvalidSection1, /**< A section was declared without quotes, and had extra tokens */
|
SMCError_InvalidSection1, /**< A section was declared without quotes, and had extra tokens */
|
||||||
SMCParse_InvalidSection2, /**< A section was declared without any header */
|
SMCError_InvalidSection2, /**< A section was declared without any header */
|
||||||
SMCParse_InvalidSection3, /**< A section ending was declared with too many unknown tokens */
|
SMCError_InvalidSection3, /**< A section ending was declared with too many unknown tokens */
|
||||||
SMCParse_InvalidSection4, /**< A section ending has no matching beginning */
|
SMCError_InvalidSection4, /**< A section ending has no matching beginning */
|
||||||
SMCParse_InvalidSection5, /**< A section beginning has no matching ending */
|
SMCError_InvalidSection5, /**< A section beginning has no matching ending */
|
||||||
SMCParse_InvalidTokens, /**< There were too many unidentifiable strings on one line */
|
SMCError_InvalidTokens, /**< There were too many unidentifiable strings on one line */
|
||||||
SMCParse_TokenOverflow, /**< The token buffer overflowed */
|
SMCError_TokenOverflow, /**< The token buffer overflowed */
|
||||||
SMCParse_InvalidProperty1, /**< A property was declared outside of any section */
|
SMCError_InvalidProperty1, /**< A property was declared outside of any section */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief States for line/column
|
||||||
|
*/
|
||||||
|
struct SMCStates
|
||||||
|
{
|
||||||
|
unsigned int line; /**< Current line */
|
||||||
|
unsigned int col; /**< Current col */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -214,6 +235,14 @@ namespace SourceMod
|
|||||||
*/
|
*/
|
||||||
class ITextListener_SMC
|
class ITextListener_SMC
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Returns version number.
|
||||||
|
*/
|
||||||
|
virtual unsigned int GetTextParserVersion2()
|
||||||
|
{
|
||||||
|
return SMINTERFACE_TEXTPARSERS_VERSION;
|
||||||
|
}
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Called when starting parsing.
|
* @brief Called when starting parsing.
|
||||||
@ -232,73 +261,58 @@ namespace SourceMod
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Called when a warning occurs.
|
|
||||||
* @param error By-reference variable containing the error message of the warning.
|
|
||||||
* @param tokens Pointer to the token stream causing the error.
|
|
||||||
* @return SMCParseResult directive.
|
|
||||||
*/
|
|
||||||
virtual SMCParseResult ReadSMC_OnWarning(SMCParseError &error, const char *tokens)
|
|
||||||
{
|
|
||||||
return SMCParse_HaltFail;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Called when entering a new section
|
* @brief Called when entering a new section
|
||||||
*
|
*
|
||||||
|
* @param states Parsing states.
|
||||||
* @param name Name of section, with the colon omitted.
|
* @param name Name of section, with the colon omitted.
|
||||||
* @param opt_quotes Whether or not the option string was enclosed in quotes.
|
* @return SMCResult directive.
|
||||||
* @return SMCParseResult directive.
|
|
||||||
*/
|
*/
|
||||||
virtual SMCParseResult ReadSMC_NewSection(const char *name, bool opt_quotes)
|
virtual SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name)
|
||||||
{
|
{
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Called when encountering a key/value pair in a section.
|
* @brief Called when encountering a key/value pair in a section.
|
||||||
*
|
*
|
||||||
|
* @param states Parsing states.
|
||||||
* @param key Key string.
|
* @param key Key string.
|
||||||
* @param value Value string. If no quotes were specified, this will be NULL,
|
* @param value Value string. If no quotes were specified, this will be NULL,
|
||||||
and key will contain the entire string.
|
* and key will contain the entire string.
|
||||||
* @param key_quotes Whether or not the key was in quotation marks.
|
* @param Number of line in file.
|
||||||
* @param value_quotes Whether or not the value was in quotation marks.
|
* @return SMCResult directive.
|
||||||
* @return SMCParseResult directive.
|
|
||||||
*/
|
*/
|
||||||
virtual SMCParseResult ReadSMC_KeyValue(const char *key,
|
virtual SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
|
||||||
const char *value,
|
|
||||||
bool key_quotes,
|
|
||||||
bool value_quotes)
|
|
||||||
{
|
{
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Called when leaving the current section.
|
* @brief Called when leaving the current section.
|
||||||
*
|
*
|
||||||
* @return SMCParseResult directive.
|
* @param Parsing states.
|
||||||
|
* @return SMCResult directive.
|
||||||
*/
|
*/
|
||||||
virtual SMCParseResult ReadSMC_LeavingSection()
|
virtual SMCResult ReadSMC_LeavingSection(const SMCStates *states)
|
||||||
{
|
{
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Called after an input line has been preprocessed.
|
* @brief Called after an input line has been preprocessed.
|
||||||
*
|
*
|
||||||
* @param line String containing line input.
|
* @param states Parsing states.
|
||||||
* @param curline Number of line in file.
|
* @param line Contents of the line, null terminated at the position
|
||||||
* @return SMCParseResult directive.
|
* of the newline character (thus, no newline will exist).
|
||||||
|
* @return SMCResult directive.
|
||||||
*/
|
*/
|
||||||
virtual SMCParseResult ReadSMC_RawLine(const char *line, unsigned int curline)
|
virtual SMCResult ReadSMC_RawLine(const SMCStates *states, const char *line)
|
||||||
{
|
{
|
||||||
return SMCParse_Continue;
|
return SMCResult_Continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SMINTERFACE_TEXTPARSERS_NAME "ITextParsers"
|
|
||||||
#define SMINTERFACE_TEXTPARSERS_VERSION 1
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Contains various text stream parsing functions.
|
* @brief Contains various text stream parsing functions.
|
||||||
*/
|
*/
|
||||||
@ -313,6 +327,14 @@ namespace SourceMod
|
|||||||
{
|
{
|
||||||
return SMINTERFACE_TEXTPARSERS_VERSION;
|
return SMINTERFACE_TEXTPARSERS_VERSION;
|
||||||
}
|
}
|
||||||
|
virtual bool IsVersionCompatible(unsigned int version)
|
||||||
|
{
|
||||||
|
if (version < 2)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return SMInterface::IsVersionCompatible(version);
|
||||||
|
}
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Parses an INI-format file.
|
* @brief Parses an INI-format file.
|
||||||
@ -336,22 +358,20 @@ namespace SourceMod
|
|||||||
*
|
*
|
||||||
* @param file Path to file.
|
* @param file Path to file.
|
||||||
* @param smc_listener Event handler for reading file.
|
* @param smc_listener Event handler for reading file.
|
||||||
* @param line If non-NULL, will contain last line parsed (0 if file could not be opened).
|
* @param states Optional pointer to store last known states.
|
||||||
* @param col If non-NULL, will contain last column parsed (undefined if file could not be opened).
|
* @return An SMCError result code.
|
||||||
* @return An SMCParseError result code.
|
|
||||||
*/
|
*/
|
||||||
virtual SMCParseError ParseFile_SMC(const char *file,
|
virtual SMCError ParseFile_SMC(const char *file,
|
||||||
ITextListener_SMC *smc_listener,
|
ITextListener_SMC *smc_listener,
|
||||||
unsigned int *line,
|
SMCStates *states) =0;
|
||||||
unsigned int *col) =0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Converts an SMCParseError to a string.
|
* @brief Converts an SMCError to a string.
|
||||||
*
|
*
|
||||||
* @param err SMCParseError.
|
* @param err SMCError.
|
||||||
* @return String error message, or NULL if none.
|
* @return String error message, or NULL if none.
|
||||||
*/
|
*/
|
||||||
virtual const char *GetSMCErrorString(SMCParseError err) =0;
|
virtual const char *GetSMCErrorString(SMCError err) =0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
@ -395,3 +415,4 @@ namespace SourceMod
|
|||||||
extern SourceMod::ITextParsers *textparsers;
|
extern SourceMod::ITextParsers *textparsers;
|
||||||
|
|
||||||
#endif //_INCLUDE_SOURCEMOD_TEXTPARSERS_INTERFACE_H_
|
#endif //_INCLUDE_SOURCEMOD_TEXTPARSERS_INTERFACE_H_
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user