diff --git a/core/AdminCache.cpp b/core/AdminCache.cpp index a89fae1e..f8c880e3 100644 --- a/core/AdminCache.cpp +++ b/core/AdminCache.cpp @@ -82,22 +82,21 @@ public: private: bool Parse() { - unsigned int line = 0; - SMCParseError error; + SMCStates states; + SMCError error; - m_Line = 0; m_bFileNameLogged = false; g_SourceMod.BuildPath(Path_SM, m_File, sizeof(m_File), "configs/admin_levels.cfg"); - if ((error = textparsers->ParseFile_SMC(m_File, this, &line, NULL)) - != SMCParse_Okay) + if ((error = textparsers->ParseFile_SMC(m_File, this, &states)) + != SMCError_Okay) { const char *err_string = textparsers->GetSMCErrorString(error); if (!err_string) { err_string = "Unknown error"; } - ParseError("Error %d (%s)", error, err_string); + ParseError(NULL, "Error %d (%s)", error, err_string); return false; } @@ -109,12 +108,12 @@ private: m_IgnoreLevel = 0; 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) { m_IgnoreLevel++; - return SMCParse_Continue; + return SMCResult_Continue; } if (m_LevelState == LEVEL_STATE_NONE) @@ -122,35 +121,41 @@ private: if (strcmp(name, "Levels") == 0) { m_LevelState = LEVEL_STATE_LEVELS; - } else { + } + else + { m_IgnoreLevel++; } } else if (m_LevelState == LEVEL_STATE_LEVELS) { if (strcmp(name, "Flags") == 0) { m_LevelState = LEVEL_STATE_FLAGS; - } else { + } + else + { m_IgnoreLevel++; } - } else { + } + else + { 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) { - return SMCParse_Continue; + return SMCResult_Continue; } unsigned char c = (unsigned)value[0]; if (c < (unsigned)'a' || c > (unsigned)'z') { - ParseError("Flag \"%c\" is not a lower-case ASCII letter", c); - return SMCParse_Continue; + ParseError(states, "Flag \"%c\" is not a lower-case ASCII letter", c); + return SMCResult_Continue; } c -= (unsigned)'a'; @@ -159,38 +164,35 @@ private: if (!g_Admins.FindFlag(key, &g_FlagLetters[c])) { - ParseError("Unrecognized admin level \"%s\"", key); - return SMCParse_Continue; + ParseError(states, "Unrecognized admin level \"%s\"", key); + return SMCResult_Continue; } g_FlagSet[c] = true; - return SMCParse_Continue; + return SMCResult_Continue; } - SMCParseResult ReadSMC_LeavingSection() + SMCResult ReadSMC_LeavingSection(const SMCStates *states) { if (m_IgnoreLevel) { m_IgnoreLevel--; - return SMCParse_Continue; + return SMCResult_Continue; } if (m_LevelState == LEVEL_STATE_FLAGS) { m_LevelState = LEVEL_STATE_LEVELS; - return SMCParse_Halt; - } else if (m_LevelState == LEVEL_STATE_LEVELS) { + return SMCResult_Halt; + } + else if (m_LevelState == LEVEL_STATE_LEVELS) + { m_LevelState = LEVEL_STATE_NONE; } - return SMCParse_Continue; + return SMCResult_Continue; } - SMCParseResult ReadSMC_RawLine(const char *line, unsigned int curline) - { - m_Line = curline; - return SMCParse_Continue; - } - void ParseError(const char *message, ...) + void ParseError(const SMCStates *states, const char *message, ...) { va_list ap; char buffer[256]; @@ -205,14 +207,13 @@ private: 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: bool m_bFileNameLogged; char m_File[PLATFORM_MAX_PATH]; int m_LevelState; int m_IgnoreLevel; - unsigned int m_Line; } s_FlagReader; AdminCache::AdminCache() diff --git a/core/CoreConfig.cpp b/core/CoreConfig.cpp index d9b364dc..dab545bb 100644 --- a/core/CoreConfig.cpp +++ b/core/CoreConfig.cpp @@ -100,7 +100,7 @@ void CoreConfig::OnRootConsoleCommand(const char *cmdname, const CCommand &comma void CoreConfig::Initialize() { - SMCParseError err; + SMCError err; char filePath[PLATFORM_MAX_PATH]; /* 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); /* 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 */ 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]; 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); } - return SMCParse_Continue; + return SMCResult_Continue; } ConfigResult CoreConfig::SetConfigOption(const char *option, const char *value, ConfigSource source, char *error, size_t maxlength) diff --git a/core/CoreConfig.h b/core/CoreConfig.h index 73398e97..2de99a33 100644 --- a/core/CoreConfig.h +++ b/core/CoreConfig.h @@ -48,7 +48,7 @@ public: // SMGlobalClass void OnSourceModShutdown(); void OnSourceModLevelChange(const char *mapName); 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 void OnRootConsoleCommand(const char *cmdname, const CCommand &command); public: diff --git a/core/Database.cpp b/core/Database.cpp index a1e58631..5efd0d6f 100644 --- a/core/Database.cpp +++ b/core/Database.cpp @@ -75,21 +75,21 @@ void DBManager::OnSourceModAllInitialized() void DBManager::OnSourceModLevelChange(const char *mapName) { - SMCParseError err; - unsigned int line = 0; + SMCError err; + SMCStates states = {0, 0}; /* 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 * potentially empty/corrupt list, which would be very bad. */ 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); - if (err != SMCParse_Custom) + if (err != SMCError_Custom) { 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(); @@ -141,12 +141,12 @@ void DBManager::ReadSMC_ParseStart() } 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) { m_ParseLevel++; - return SMCParse_Continue; + return SMCResult_Continue; } if (m_ParseState == DBPARSE_LEVEL_NONE) @@ -165,14 +165,14 @@ SMCParseResult DBManager::ReadSMC_NewSection(const char *name, bool opt_quotes) 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) { - return SMCParse_Continue; + return SMCResult_Continue; } 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) \ @@ -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); \ } -SMCParseResult DBManager::ReadSMC_LeavingSection() +SMCResult DBManager::ReadSMC_LeavingSection(const SMCStates *states) { if (m_ParseLevel) { m_ParseLevel--; - return SMCParse_Continue; + return SMCResult_Continue; } if (m_ParseState == DBPARSE_LEVEL_DATABASE) @@ -239,10 +239,10 @@ SMCParseResult DBManager::ReadSMC_LeavingSection() m_ParseState = DBPARSE_LEVEL_MAIN; } else if (m_ParseState == DBPARSE_LEVEL_MAIN) { m_ParseState = DBPARSE_LEVEL_NONE; - return SMCParse_Halt; + return SMCResult_Halt; } - return SMCParse_Continue; + return SMCResult_Continue; } #undef ASSIGN_VAR diff --git a/core/Database.h b/core/Database.h index f3f8db4f..aae09862 100644 --- a/core/Database.h +++ b/core/Database.h @@ -94,9 +94,9 @@ public: //IDBManager HandleError ReleaseHandle(Handle_t hndl, DBHandleType type, IdentityToken_t *token); public: //ITextListener_SMC void ReadSMC_ParseStart(); - 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(); + 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); public: //IThread void RunThread(IThreadHandle *pThread); diff --git a/core/GameConfigs.cpp b/core/GameConfigs.cpp index d3c790ef..86b87f99 100644 --- a/core/GameConfigs.cpp +++ b/core/GameConfigs.cpp @@ -106,12 +106,12 @@ CGameConfig::~CGameConfig() 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) { m_IgnoreLevel++; - return SMCParse_Continue; + return SMCResult_Continue; } 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) { - return SMCParse_Continue; + return SMCResult_Continue; } 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) { m_IgnoreLevel--; - return SMCParse_Continue; + return SMCResult_Continue; } switch (m_ParseState) @@ -478,12 +478,12 @@ skip_find: } } - return SMCParse_Continue; + return SMCResult_Continue; } bool CGameConfig::Reparse(char *error, size_t maxlength) { - SMCParseError err; + SMCError err; char path[PLATFORM_MAX_PATH]; 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_pKeys); - if ((err=textparsers->ParseFile_SMC(path, this, NULL, NULL)) - != SMCParse_Okay) + if ((err=textparsers->ParseFile_SMC(path, this, NULL)) + != SMCError_Okay) { - if (error && (err != SMCParse_Custom)) + if (error && (err != SMCError_Custom)) { const char *str = textparsers->GetSMCErrorString(err); snprintf(error, maxlength, "%s", str); diff --git a/core/GameConfigs.h b/core/GameConfigs.h index 7b00aad9..f0fd35b2 100644 --- a/core/GameConfigs.h +++ b/core/GameConfigs.h @@ -55,9 +55,9 @@ public: public: bool Reparse(char *error, size_t maxlength); public: //ITextListener_SMC - 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(); + 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); public: //IGameConfig const char *GetKeyValue(const char *key); bool GetOffset(const char *key, int *value); diff --git a/core/TextParsers.cpp b/core/TextParsers.cpp index a9e07cb8..73f65b12 100644 --- a/core/TextParsers.cpp +++ b/core/TextParsers.cpp @@ -107,14 +107,13 @@ bool CharStreamReader(void *stream, char *buffer, size_t maxlength, unsigned int return true; } -SMCParseError TextParsers::ParseString_SMC(const char *stream, +SMCError TextParsers::ParseString_SMC(const char *stream, ITextListener_SMC *smc, - unsigned int *line, - unsigned int *col) + SMCStates *states) { 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); } -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"); 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); @@ -273,34 +277,44 @@ char *lowstring(StringInfo info[3]) return NULL; } -SMCParseError TextParsers::ParseStream_SMC(void *stream, +SMCError TextParsers::ParseStream_SMC(void *stream, STREAMREADER srdr, ITextListener_SMC *smc, - unsigned int *line, - unsigned int *col) + SMCStates *pStates) { char *reparse_point = NULL; char in_buf[4096]; char *parse_point = in_buf; char *line_begin = in_buf; unsigned int read; - unsigned int curline = 1; - unsigned int curtok = 0; unsigned int curlevel = 0; bool in_quote = false; bool ignoring = false; bool eol_comment = false; bool ml_comment = false; unsigned int i; - SMCParseError err = SMCParse_Okay; - SMCParseResult res; + SMCError err = SMCError_Okay; + SMCResult res; + SMCStates states; char c; StringInfo strings[3]; StringInfo emptystring; + states.line = 1; + states.col = 0; + 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)) { if (!read) @@ -308,10 +322,10 @@ SMCParseError TextParsers::ParseStream_SMC(void *stream, break; } - /* :TODO: do this outside of the main loop somehow - * This checks for BOM markings + /* Check for BOM markings, which is only relevant on the first line. + * 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[1] == (char)0xBB && in_buf[2] == (char)0xBF) @@ -341,7 +355,7 @@ SMCParseError TextParsers::ParseStream_SMC(void *stream, strings[0].end = &parse_point[i]; if (rotate(strings) != NULL) { - err = SMCParse_InvalidTokens; + err = SMCError_InvalidTokens; goto failed; } } @@ -354,39 +368,44 @@ SMCParseError TextParsers::ParseStream_SMC(void *stream, ignoring = false; } - /* Pass the raw line onto the listener */ - if ((res=smc->ReadSMC_RawLine(line_begin, curline)) != SMCParse_Continue) + /* Pass the raw line onto the listener. We terminate the line so the receiver + * 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; } + parse_point[i] = '\n'; /* Now we check the sanity of our staged strings! */ if (strings[2].ptr) { if (!curlevel) { - err = SMCParse_InvalidProperty1; + err = SMCError_InvalidProperty1; goto failed; } /* Assume the next string is a property and pass the info on. */ if ((res=smc->ReadSMC_KeyValue( + &states, FixupString(strings[2]), - FixupString(strings[1]), - strings[2].quoted, - strings[1].quoted)) != SMCParse_Continue) + FixupString(strings[1]))) != SMCResult_Continue) { - err = (res == SMCParse_HaltFail) ? SMCParse_Custom : SMCParse_Okay; + err = (res == SMCResult_HaltFail) ? SMCError_Custom : SMCError_Okay; goto failed; } scrap(strings); } /* Change the states for the next line */ - curtok = 0; - curline++; + states.col = 0; + states.line++; line_begin = &parse_point[i+1]; //Note: safe because this gets relocated later - } else if (ignoring) { + } + else if (ignoring) + { if (in_quote) { /* 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 we rotated too many strings, there was too much crap on one line */ - err = SMCParse_InvalidTokens; + err = SMCError_InvalidTokens; goto failed; } - } else if (c == '\\') { + } + else if (c == '\\') + { strings[0].special = true; if (i == (read - 1)) { @@ -414,7 +435,9 @@ SMCParseError TextParsers::ParseStream_SMC(void *stream, break; } } - } else if (ml_comment) { + } + else if (ml_comment) + { if (c == '*') { /* Check if we need to get more input first */ @@ -431,11 +454,13 @@ SMCParseError TextParsers::ParseStream_SMC(void *stream, assert(strings[0].ptr == NULL); /* Advance the input stream so we don't choke on this token */ i++; - curtok++; + states.col++; } } } - } else { + } + else + { /* Check if we're whitespace or not */ if (!g_ws_chartable[(unsigned)c]) { @@ -468,7 +493,9 @@ SMCParseError TextParsers::ParseStream_SMC(void *stream, ignoring = true; eol_comment = true; restage = true; - } else if (parse_point[i+1] == '*') { + } + else if (parse_point[i+1] == '*') + { /* inline comment - start ignoring */ ignoring = true; ml_comment = true; @@ -479,93 +506,108 @@ SMCParseError TextParsers::ParseStream_SMC(void *stream, */ restage = true; } - } else { + } + else + { ignoring = true; eol_comment = true; restage = true; } - } else if (c == '{') { + } + else if (c == '{') + { /* If we are staging a string, we must rotate here */ if (strings[0].ptr) { /* We have unacceptable tokens on this line */ if (rotate(strings) != NULL) { - err = SMCParse_InvalidSection1; + err = SMCError_InvalidSection1; goto failed; } } /* Sections must always be alone */ if (strings[2].ptr != NULL) { - err = SMCParse_InvalidSection1; + err = SMCError_InvalidSection1; goto failed; - } else if (strings[1].ptr == NULL) { - err = SMCParse_InvalidSection2; + } + else if (strings[1].ptr == NULL) + { + err = SMCError_InvalidSection2; goto failed; } - if ((res=smc->ReadSMC_NewSection(FixupString(strings[1]), strings[1].quoted)) - != SMCParse_Continue) + if ((res=smc->ReadSMC_NewSection(&states, FixupString(strings[1]))) + != SMCResult_Continue) { - err = (res == SMCParse_HaltFail) ? SMCParse_Custom : SMCParse_Okay; + err = (res == SMCResult_HaltFail) ? SMCError_Custom : SMCError_Okay; goto failed; } strings[1] = emptystring; curlevel++; - } else if (c == '}') { + } + else if (c == '}') + { /* Unlike our matching friend, this can be on the same line as something prior */ if (rotate(strings) != NULL) { - err = SMCParse_InvalidSection3; + err = SMCError_InvalidSection3; goto failed; } if (strings[2].ptr) { if (!curlevel) { - err = SMCParse_InvalidProperty1; + err = SMCError_InvalidProperty1; goto failed; } if ((res=smc->ReadSMC_KeyValue( + &states, FixupString(strings[2]), - FixupString(strings[1]), - strings[2].quoted, - strings[1].quoted)) - != SMCParse_Continue) + FixupString(strings[1]))) + != SMCResult_Continue) { - err = (res == SMCParse_HaltFail) ? SMCParse_Custom : SMCParse_Okay; + err = (res == SMCResult_HaltFail) ? SMCError_Custom : SMCError_Okay; goto failed; } - } else if (strings[1].ptr) { - err = SMCParse_InvalidSection3; + } + else if (strings[1].ptr) + { + err = SMCError_InvalidSection3; goto failed; - } else if (!curlevel) { - err = SMCParse_InvalidSection4; + } + else if (!curlevel) + { + err = SMCError_InvalidSection4; goto failed; } /* Now it's safe to leave the section */ 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; } curlevel--; - } else if (c == '"') { + } + else if (c == '"') + { /* If we get a quote mark, we always restage, but we need to do it beforehand */ if (strings[0].ptr) { strings[0].end = &parse_point[i]; if (rotate(strings) != NULL) { - err = SMCParse_InvalidTokens; + err = SMCError_InvalidTokens; goto failed; } } strings[0].ptr = &parse_point[i]; in_quote = true; ignoring = true; - } else if (!strings[0].ptr) { + } + else if (!strings[0].ptr) + { /* If we have no string, we must start one */ strings[0].ptr = &parse_point[i]; } @@ -574,11 +616,13 @@ SMCParseError TextParsers::ParseStream_SMC(void *stream, strings[0].end = &parse_point[i]; if (rotate(strings) != NULL) { - err = SMCParse_InvalidTokens; + err = SMCError_InvalidTokens; goto failed; } } - } else { + } + else + { /* If we're eating a string and get whitespace, we need to restage. * (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 */ strings[0].end = &parse_point[i]; rotate(strings); - } else if (!strings[1].quoted) { - err = SMCParse_InvalidTokens; + } + else if (!strings[1].quoted) + { + err = SMCError_InvalidTokens; goto failed; } } @@ -603,7 +649,7 @@ SMCParseError TextParsers::ParseStream_SMC(void *stream, } /* Advance which token we're on */ - curtok++; + states.col++; } if (line_begin != in_buf) @@ -637,8 +683,10 @@ SMCParseError TextParsers::ParseStream_SMC(void *stream, parse_point = &parse_point[read]; 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; } } @@ -646,29 +694,31 @@ SMCParseError TextParsers::ParseStream_SMC(void *stream, /* If we're done parsing and there are tokens left over... */ if (curlevel) { - err = SMCParse_InvalidSection5; + err = SMCError_InvalidSection5; 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; } smc->ReadSMC_ParseEnd(false, false); + + if (pStates != NULL) + { + *pStates = states; + } - return SMCParse_Okay; + return SMCError_Okay; failed: - if (line) + if (pStates != NULL) { - *line = curline; + *pStates = states; } - smc->ReadSMC_ParseEnd(true, (err == SMCParse_Custom)); - - if (col) - { - *col = curtok; - } + smc->ReadSMC_ParseEnd(true, (err == SMCError_Custom)); return err; } @@ -976,7 +1026,7 @@ event_failed: return false; } -const char *TextParsers::GetSMCErrorString(SMCParseError err) +const char *TextParsers::GetSMCErrorString(SMCError err) { static const char *s_errors[] = { @@ -994,7 +1044,7 @@ const char *TextParsers::GetSMCErrorString(SMCParseError err) "A property was declared outside of a section", }; - if (err < SMCParse_Okay || err > SMCParse_InvalidProperty1) + if (err < SMCError_Okay || err > SMCError_InvalidProperty1) { return NULL; } diff --git a/core/TextParsers.h b/core/TextParsers.h index 2dfda119..6065b0cf 100644 --- a/core/TextParsers.h +++ b/core/TextParsers.h @@ -60,28 +60,26 @@ public: unsigned int *line, unsigned int *col); - SMCParseError ParseFile_SMC(const char *file, + SMCError ParseFile_SMC(const char *file, ITextListener_SMC *smc_listener, - unsigned int *line, - unsigned int *col); + SMCStates *states); unsigned int GetUTF8CharBytes(const char *stream); - const char *GetSMCErrorString(SMCParseError err); + const char *GetSMCErrorString(SMCError err); bool IsWhitespace(const char *stream); private: - SMCParseError ParseString_SMC(const char *stream, + SMCError ParseString_SMC(const char *stream, ITextListener_SMC *smc, - unsigned int *line, - unsigned int *col); - SMCParseError ParseStream_SMC(void *stream, + SMCStates *states); + SMCError ParseStream_SMC(void *stream, STREAMREADER srdr, ITextListener_SMC *smc, - unsigned int *line, - unsigned int *col); + SMCStates *states); }; extern TextParsers g_TextParser; #endif //_INCLUDE_SOURCEMOD_TEXTPARSERS_H_ + diff --git a/core/Translator.cpp b/core/Translator.cpp index 20a708d3..eb6bc92e 100644 --- a/core/Translator.cpp +++ b/core/Translator.cpp @@ -119,7 +119,7 @@ void CPhraseFile::ReparseFile() return; } - SMCParseError err; + SMCError err; char path[PLATFORM_MAX_PATH]; 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); 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] 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_ParseState = PPS_None; - m_CurLine = 0; m_FileLogged = false; m_LastPhraseString.clear(); } -SMCParseResult CPhraseFile::ReadSMC_RawLine(const char *line, unsigned int curline) -{ - m_CurLine = curline; - - return SMCParse_Continue; -} - -SMCParseResult CPhraseFile::ReadSMC_NewSection(const char *name, bool opt_quotes) +SMCResult CPhraseFile::ReadSMC_NewSection(const SMCStates *states, const char *name) { bool recognized = false; if (m_ParseState == PPS_None) @@ -178,7 +170,9 @@ SMCParseResult CPhraseFile::ReadSMC_NewSection(const char *name, bool opt_quotes m_ParseState = PPS_Phrases; recognized = true; } - } else if (m_ParseState == PPS_Phrases) { + } + else if (m_ParseState == PPS_Phrases) + { m_ParseState = PPS_InPhrase; recognized = true; @@ -188,10 +182,12 @@ SMCParseResult CPhraseFile::ReadSMC_NewSection(const char *name, bool opt_quotes /* Create the reverse lookup */ if (!sm_trie_insert(m_pPhraseLookup, name, reinterpret_cast(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? */ m_CurPhrase = -1; - } else { + } + else + { /* Initialize new phrase */ trans_t *pTrans; @@ -211,25 +207,27 @@ SMCParseResult CPhraseFile::ReadSMC_NewSection(const char *name, bool opt_quotes } m_LastPhraseString.assign(name); } - } else if (m_ParseState == PPS_InPhrase) { + } + else if (m_ParseState == PPS_InPhrase) + { ParseError("Phrase sections may not have sub-sections"); - return SMCParse_HaltFail; + return SMCResult_HaltFail; } 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 */ if (m_CurPhrase == -1) { - return SMCParse_Continue; + return SMCResult_Continue; } 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) { - ParseWarning("Ignoring duplicated #format property on line %d", m_CurLine); - return SMCParse_Continue; + ParseWarning("Ignoring duplicated #format property on line %d", states->line); + return SMCResult_Continue; } if (pPhrase->translations > 0) { - ParseWarning("#format property should come before translations on line %d, ignoring", m_CurLine); - return SMCParse_Continue; + ParseWarning("#format property should come before translations on line %d, ignoring", states->line); + return SMCResult_Continue; } /* 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++; state = Parse_Index; - } else if (*value == ',') { + } + else if (*value == ',') + { /* Do nothing */ - } else { + } + else + { unsigned int bytes = textparsers->GetUTF8CharBytes(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 == ':') { state = Parse_Format; 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; - return SMCParse_Continue; + return SMCResult_Continue; } - } else { + } + else + { unsigned int bytes = textparsers->GetUTF8CharBytes(value); if (bytes != 1 || !isdigit(*value)) { ParseWarning("Token '%c' in #format property on line %d is not a digit, phrase will be ignored.", *value, - m_CurLine); + states->line); m_CurPhrase = -1; - return SMCParse_Continue; + return SMCResult_Continue; } } - } else if (state == Parse_Format) { + } + else if (state == Parse_Format) + { if (*value == '}') { state = Parse_None; @@ -311,9 +319,9 @@ SMCParseResult CPhraseFile::ReadSMC_KeyValue(const char *key, const char *value, if (state != Parse_None) { /* 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; - return SMCParse_Continue; + return SMCResult_Continue; } value = old_value; @@ -347,41 +355,49 @@ SMCParseResult CPhraseFile::ReadSMC_KeyValue(const char *key, const char *value, state = Parse_Index; idx_ptr = NULL; } - } else if (state == Parse_Index) { + } + else if (state == Parse_Index) + { if (*in_ptr == ':') { /* Check the number! */ 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; - return SMCParse_Continue; + return SMCResult_Continue; } long idx = strtol(idx_ptr, NULL, 10); 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; - return SMCParse_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); + 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, states->line); m_CurPhrase = -1; - return SMCParse_Continue; + return SMCResult_Continue; } cur_idx = (unsigned int)idx; state = Parse_Format; out_ptr = NULL; - } else if (!idx_ptr) { + } + else if (!idx_ptr) + { idx_ptr = in_ptr; } - } else if (state == Parse_Format) { + } + else if (state == Parse_Format) + { if (*in_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; - return SMCParse_Continue; + return SMCResult_Continue; } *out_ptr = '\0'; state = Parse_None; @@ -392,7 +408,9 @@ SMCParseResult CPhraseFile::ReadSMC_KeyValue(const char *key, const char *value, pPhrase->fmt_bytes += strlen(fmt_buf); fmt_list = (int *)m_pMemory->GetAddress(pPhrase->fmt_list); fmt_list[cur_idx - 1] = tmp_idx; - } else { + } + else + { if (!out_ptr) { 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) { ParseWarning("Format property contains format string that exceeds maximum length on line %d, phrase will be ignored.", - m_CurLine); + states->line); m_CurPhrase = -1; - return SMCParse_Continue; + return SMCResult_Continue; } *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.", i + 1, - m_CurLine); + states->line); m_CurPhrase = -1; - return SMCParse_Continue; + return SMCResult_Continue; } } - } else { + } + else + { size_t len = strlen(key); if (len != 2) { - ParseWarning("Ignoring translation to invalid language \"%s\" on line %d.", key, m_CurLine); - return SMCParse_Continue; + ParseWarning("Ignoring translation to invalid language \"%s\" on line %d.", key, states->line); + return SMCResult_Continue; } 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. * :IDEA: issue a one-time alert? */ - return SMCParse_Continue; + return SMCResult_Continue; } /* 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 */ 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 */ const char *scrap_in_point = in_ptr; const char *digit_start = ++in_ptr; @@ -570,10 +592,10 @@ cont_loop: pPhrase->translations++; } - return SMCParse_Continue; + return SMCResult_Continue; } -SMCParseResult CPhraseFile::ReadSMC_LeavingSection() +SMCResult CPhraseFile::ReadSMC_LeavingSection(const SMCStates *states) { if (m_ParseState == PPS_InPhrase) { @@ -584,11 +606,13 @@ SMCParseResult CPhraseFile::ReadSMC_LeavingSection() m_CurPhrase = -1; m_ParseState = PPS_Phrases; m_LastPhraseString.assign(""); - } else if (m_ParseState == PPS_Phrases) { + } + else if (m_ParseState == PPS_Phrases) + { m_ParseState = PPS_None; } - return SMCParse_Continue; + return SMCResult_Continue; } 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; } - pTrans->fmt_order = (int *)m_pMemory->GetAddress(trans->fmt_order); 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); return Trans_Okay; @@ -811,9 +834,9 @@ void Translator::RebuildLanguageDatabase(const char *lang_header_file) m_Languages.clear(); /* Start anew */ - SMCParseError err; - unsigned int line=0, col=0; - if ((err=textparsers->ParseFile_SMC(lang_header_file, this, &line, &col)) != SMCParse_Okay) + SMCError err; + SMCStates states; + if ((err=textparsers->ParseFile_SMC(lang_header_file, this, &states)) != SMCError_Okay) { const char *str_err = textparsers->GetSMCErrorString(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] 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; @@ -854,7 +877,7 @@ void Translator::ReadSMC_ParseStart() 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) { @@ -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); } - return SMCParse_Continue; + return SMCResult_Continue; } -SMCParseResult Translator::ReadSMC_LeavingSection() +SMCResult Translator::ReadSMC_LeavingSection(const SMCStates *states) { 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); @@ -891,7 +914,7 @@ SMCParseResult Translator::ReadSMC_KeyValue(const char *key, const char *value, AddLanguage(key, value); - return SMCParse_Continue; + return SMCResult_Continue; } bool Translator::AddLanguage(const char *langcode, const char *description) diff --git a/core/Translator.h b/core/Translator.h index 755cbb36..6ae3b13f 100644 --- a/core/Translator.h +++ b/core/Translator.h @@ -89,11 +89,10 @@ public: TransError GetTranslation(const char *szPhrase, unsigned int lang_id, Translation *pTrans); public: //ITextListener_SMC 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); - 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: void ParseError(const char *message, ...); void ParseWarning(const char *message, ...); @@ -108,7 +107,6 @@ private: unsigned int m_LangCount; String m_ParseError; String m_LastPhraseString; - unsigned int m_CurLine; bool m_FileLogged; }; @@ -129,9 +127,9 @@ public: // SMGlobalClass void OnSourceModLevelChange(const char *mapName); public: // ITextListener_SMC void ReadSMC_ParseStart(); - 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(); + 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); public: void RebuildLanguageDatabase(const char *lang_header_file); unsigned int FindOrAddPhraseFile(const char *phrase_file); diff --git a/core/smn_textparse.cpp b/core/smn_textparse.cpp index 1c37fdc1..38a23e24 100644 --- a/core/smn_textparse.cpp +++ b/core/smn_textparse.cpp @@ -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) { new_section->PushCell(handle); new_section->PushString(name); - new_section->PushCell(opt_quotes ? 1 : 0); + new_section->PushCell(1); 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) { key_value->PushCell(handle); key_value->PushString(key); key_value->PushString(value); - key_value->PushCell(key_quotes ? 1 : 0); - key_value->PushCell(value_quotes ? 1 : 0); + key_value->PushCell(1); + key_value->PushCell(1); 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) { @@ -113,22 +113,22 @@ public: 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) { raw_line->PushCell(handle); raw_line->PushString(line); - raw_line->PushCell(curline); + raw_line->PushCell(states->line); raw_line->Execute(&result); } - return (SMCParseResult)result; + return (SMCResult)result; } public: IPluginFunction *parse_start; @@ -279,22 +279,22 @@ static cell_t SMC_ParseFile(IPluginContext *pContext, const cell_t *params) char path[PLATFORM_MAX_PATH]; g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "%s", file); - unsigned int line = 0, col = 0; - SMCParseError p_err = textparsers->ParseFile_SMC(path, parse, &line, &col); + SMCStates states; + SMCError p_err = textparsers->ParseFile_SMC(path, parse, &states); cell_t *c_line, *c_col; pContext->LocalToPhysAddr(params[3], &c_line); pContext->LocalToPhysAddr(params[4], &c_col); - *c_line = line; - *c_col = col; + *c_line = states.line; + *c_col = states.col; return (cell_t)p_err; } 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) { diff --git a/core/systems/PluginInfoDatabase.cpp b/core/systems/PluginInfoDatabase.cpp index 82d50185..a8be1601 100644 --- a/core/systems/PluginInfoDatabase.cpp +++ b/core/systems/PluginInfoDatabase.cpp @@ -82,7 +82,7 @@ void CPluginInfoDatabase::ReadSMC_ParseStart() m_infodb = -1; } -SMCParseResult CPluginInfoDatabase::MakeError(const char *fmt, ...) +SMCResult CPluginInfoDatabase::MakeError(const char *fmt, ...) { char buffer[512]; va_list ap; @@ -93,7 +93,7 @@ SMCParseResult CPluginInfoDatabase::MakeError(const char *fmt, ...) m_errmsg = m_strtab->AddString(buffer); - return SMCParse_HaltFail; + return SMCResult_HaltFail; } unsigned int CPluginInfoDatabase::GetSettingsNum() @@ -149,10 +149,7 @@ void CPluginInfoDatabase::GetOptionsForPlugin(PluginSettings *settings, unsigned *val = m_strtab->GetString(table[opt_num].val); } -SMCParseResult CPluginInfoDatabase::ReadSMC_KeyValue(const char *key, - const char *value, - bool key_quotes, - bool value_quotes) +SMCResult CPluginInfoDatabase::ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value) { if (cur_plugin != -1) { @@ -164,28 +161,46 @@ SMCParseResult CPluginInfoDatabase::ReadSMC_KeyValue(const char *key, if (strcasecmp(value, "yes") == 0) { plugin->pause_val = true; - } else { + } + else + { plugin->pause_val = false; } - } else if (strcmp(key, "lifetime") == 0) { + } + else if (strcmp(key, "lifetime") == 0) + { if (strcasecmp(value, "private") == 0) { plugin->type_val = PluginType_Private; - } else if (strcasecmp(value, "mapsync") == 0) { + } + else if (strcasecmp(value, "mapsync") == 0) + { plugin->type_val = PluginType_MapUpdated; - } else if (strcasecmp(value, "maponly") == 0) { + } + else if (strcasecmp(value, "maponly") == 0) + { plugin->type_val = PluginType_MapOnly; - } else if (strcasecmp(value, "global") == 0) { + } + else if (strcasecmp(value, "global") == 0) + { plugin->type_val = PluginType_Global; - } else { + } + else + { 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; - } else { + } + else + { return MakeError("Unknown property key: \"%s\"", key); } - } else { + } + else + { /* Cache every option, valid or not */ int keyidx = m_strtab->AddString(key); int validx = m_strtab->AddString(value); @@ -199,7 +214,9 @@ SMCParseResult CPluginInfoDatabase::ReadSMC_KeyValue(const char *key, { //right now we don't have many plugin->opts_size = 2; - } else { + } + else + { plugin->opts_size *= 2; } 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)); } plugin->optarray = newidx; - } else { + } + else + { table = (PluginOpts *)memtab->GetAddress(plugin->optarray); } PluginOpts *opt = &table[plugin->opts_num++]; opt->key = keyidx; opt->val = validx; } - } else if (in_plugins) { + } + else if (in_plugins) + { return MakeError("Unknown property key: \"%s\"", key); - } else { + } + else + { /* 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) { @@ -236,7 +259,9 @@ SMCParseResult CPluginInfoDatabase::ReadSMC_LeavingSection() if (in_options) { in_options = false; - } else { + } + else + { /* If the plugin is ending, add it to the table */ BaseMemTable *memtab = m_strtab->GetMemTable(); int *table; @@ -246,7 +271,9 @@ SMCParseResult CPluginInfoDatabase::ReadSMC_LeavingSection() if (!m_infodb_size) { m_infodb_size = 8; - } else { + } + else + { m_infodb_size *= 2; } int newidx = memtab->CreateMem(m_infodb_size, (void **)&table); @@ -256,22 +283,26 @@ SMCParseResult CPluginInfoDatabase::ReadSMC_LeavingSection() memcpy(table, oldtable, oldsize * sizeof(int)); } m_infodb = newidx; - } else { + } + else + { table = (int *)memtab->GetAddress(m_infodb); } /* Assign to table and scrap the current plugin */ table[m_infodb_count++] = cur_plugin; cur_plugin = -1; } - } else { + } + else + { 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) { @@ -279,13 +310,17 @@ SMCParseResult CPluginInfoDatabase::ReadSMC_NewSection(const char *name, bool op if (strcmp(name, "Plugins") != 0) { return MakeError("Unknown root section: \"%s\"", name); - } else { + } + else + { /* Otherwise set our states */ in_plugins = true; cur_plugin = -1; in_options = false; } - } else { + } + else + { if (cur_plugin == -1) { /* 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->name = i_name; in_options = false; - } else { + } + else + { if (!in_options && strcmp(name, "Options") == 0) { in_options = true; - } else { + } + else + { return MakeError("Unknown plugin sub-section: \"%s\"", name); } } } - return SMCParse_Continue; + return SMCResult_Continue; } + diff --git a/core/systems/PluginInfoDatabase.h b/core/systems/PluginInfoDatabase.h index 51f38926..16ed542a 100644 --- a/core/systems/PluginInfoDatabase.h +++ b/core/systems/PluginInfoDatabase.h @@ -68,9 +68,9 @@ public: ~CPluginInfoDatabase(); public: //ITextListener_SMC void ReadSMC_ParseStart(); - 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(); + 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); public: /** * 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); private: - SMCParseResult MakeError(const char *fmt, ...); + SMCResult MakeError(const char *fmt, ...); private: BaseStringTable *m_strtab; int m_errmsg; diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index a7bb7341..a0bdcce4 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -819,10 +819,10 @@ void CPluginManager::Shutdown() void CPluginManager::LoadAll_FirstPass(const char *config, const char *basedir) { /* First read in the database of plugin settings */ - SMCParseError err; - unsigned int line, col; + SMCError err; + SMCStates states; 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); const char *err_msg = textparsers->GetSMCErrorString(err); diff --git a/core/vm/sp_vm_basecontext.cpp b/core/vm/sp_vm_basecontext.cpp index 0745015b..f9ad80f8 100644 --- a/core/vm/sp_vm_basecontext.cpp +++ b/core/vm/sp_vm_basecontext.cpp @@ -811,7 +811,7 @@ int BaseContext::StringToLocal(cell_t local_addr, size_t bytes, const char *sour len = bytes - 1; } - memcpy(dest, source, len); + memmove(dest, source, len); dest[len] = '\0'; return SP_ERROR_NONE; @@ -880,7 +880,7 @@ int BaseContext::StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const cha needtocheck = true; } - memcpy(dest, source, len); + memmove(dest, source, len); if ((dest[len-1] & 1<<7) && needtocheck) { len -= __CheckValidChar(dest+len-1); diff --git a/extensions/topmenus/TopMenu.cpp b/extensions/topmenus/TopMenu.cpp index e55c0c9c..bdb048a5 100644 --- a/extensions/topmenus/TopMenu.cpp +++ b/extensions/topmenus/TopMenu.cpp @@ -895,11 +895,11 @@ void TopMenu::TearDownClient(topmenu_player_t *player) bool TopMenu::LoadConfiguration(const char *file, char *error, size_t maxlength) { - SMCParseError err; - unsigned int line = 0, col = 0; + SMCError err; + SMCStates states; - if ((err = textparsers->ParseFile_SMC(file, this, &line, &col)) - != SMCParse_Okay) + if ((err = textparsers->ParseFile_SMC(file, this, &states)) + != SMCError_Okay) { const char *err_string = textparsers->GetSMCErrorString(err); if (!err_string) @@ -971,7 +971,7 @@ void TopMenu::ReadSMC_ParseStart() 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) { @@ -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 || current_parse_state != PARSE_STATE_CATEGORY || cur_cat == NULL) { - return SMCParse_Continue; + return SMCResult_Continue; } 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)); } - return SMCParse_Continue; + return SMCResult_Continue; } -SMCParseResult TopMenu::ReadSMC_LeavingSection() +SMCResult TopMenu::ReadSMC_LeavingSection(const SMCStates *states) { 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) diff --git a/extensions/topmenus/TopMenu.h b/extensions/topmenus/TopMenu.h index d9139f7b..1c80f25b 100644 --- a/extensions/topmenus/TopMenu.h +++ b/extensions/topmenus/TopMenu.h @@ -141,13 +141,10 @@ public: //IMenuHandler const ItemDrawInfo &dr); virtual void OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason); public: //ITextListener_SMC - virtual void ReadSMC_ParseStart(); - 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(); + 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); private: void SortCategoriesIfNeeded(); void SortCategoryIfNeeded(unsigned int category); diff --git a/public/ITextParsers.h b/public/ITextParsers.h index 16ccef62..0b0f0c68 100644 --- a/public/ITextParsers.h +++ b/public/ITextParsers.h @@ -41,6 +41,10 @@ namespace SourceMod { + + #define SMINTERFACE_TEXTPARSERS_NAME "ITextParsers" + #define SMINTERFACE_TEXTPARSERS_VERSION 2 + /** * The INI file format is defined as: * WHITESPACE: 0x20, \n, \t, \r @@ -85,6 +89,14 @@ namespace SourceMod */ class ITextListener_INI { + public: + /** + * @brief Returns version number. + */ + virtual unsigned int GetTextParserVersion1() + { + return SMINTERFACE_TEXTPARSERS_VERSION; + } public: /** * @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. */ - enum SMCParseResult + enum SMCResult { - SMCParse_Continue, /**< Continue parsing */ - SMCParse_Halt, /**< Stop parsing here */ - SMCParse_HaltFail /**< Stop parsing and return SMCParseError_Custom */ + SMCResult_Continue, /**< Continue parsing */ + SMCResult_Halt, /**< Stop parsing here */ + SMCResult_HaltFail /**< Stop parsing and return SMCError_Custom */ }; /** * @brief Lists error codes possible from parsing an SMC file. */ - enum SMCParseError + enum SMCError { - SMCParse_Okay = 0, /**< No error */ - SMCParse_StreamOpen, /**< Stream failed to open */ - SMCParse_StreamError, /**< The stream died... somehow */ - SMCParse_Custom, /**< A custom handler threw an error */ - SMCParse_InvalidSection1, /**< A section was declared without quotes, and had extra tokens */ - SMCParse_InvalidSection2, /**< A section was declared without any header */ - SMCParse_InvalidSection3, /**< A section ending was declared with too many unknown tokens */ - SMCParse_InvalidSection4, /**< A section ending has no matching beginning */ - SMCParse_InvalidSection5, /**< A section beginning has no matching ending */ - SMCParse_InvalidTokens, /**< There were too many unidentifiable strings on one line */ - SMCParse_TokenOverflow, /**< The token buffer overflowed */ - SMCParse_InvalidProperty1, /**< A property was declared outside of any section */ + SMCError_Okay = 0, /**< No error */ + SMCError_StreamOpen, /**< Stream failed to open */ + SMCError_StreamError, /**< The stream died... somehow */ + SMCError_Custom, /**< A custom handler threw an error */ + SMCError_InvalidSection1, /**< A section was declared without quotes, and had extra tokens */ + SMCError_InvalidSection2, /**< A section was declared without any header */ + SMCError_InvalidSection3, /**< A section ending was declared with too many unknown tokens */ + SMCError_InvalidSection4, /**< A section ending has no matching beginning */ + SMCError_InvalidSection5, /**< A section beginning has no matching ending */ + SMCError_InvalidTokens, /**< There were too many unidentifiable strings on one line */ + SMCError_TokenOverflow, /**< The token buffer overflowed */ + 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 { + public: + /** + * @brief Returns version number. + */ + virtual unsigned int GetTextParserVersion2() + { + return SMINTERFACE_TEXTPARSERS_VERSION; + } public: /** * @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 * + * @param states Parsing states. * @param name Name of section, with the colon omitted. - * @param opt_quotes Whether or not the option string was enclosed in quotes. - * @return SMCParseResult directive. + * @return SMCResult 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. * + * @param states Parsing states. * @param key Key string. * @param value Value string. If no quotes were specified, this will be NULL, - and key will contain the entire string. - * @param key_quotes Whether or not the key was in quotation marks. - * @param value_quotes Whether or not the value was in quotation marks. - * @return SMCParseResult directive. + * and key will contain the entire string. + * @param Number of line in file. + * @return SMCResult directive. */ - virtual SMCParseResult ReadSMC_KeyValue(const char *key, - const char *value, - bool key_quotes, - bool value_quotes) + virtual SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value) { - return SMCParse_Continue; + return SMCResult_Continue; } /** * @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. * - * @param line String containing line input. - * @param curline Number of line in file. - * @return SMCParseResult directive. + * @param states Parsing states. + * @param line Contents of the line, null terminated at the position + * 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. */ @@ -313,6 +327,14 @@ namespace SourceMod { return SMINTERFACE_TEXTPARSERS_VERSION; } + virtual bool IsVersionCompatible(unsigned int version) + { + if (version < 2) + { + return false; + } + return SMInterface::IsVersionCompatible(version); + } public: /** * @brief Parses an INI-format file. @@ -336,22 +358,20 @@ namespace SourceMod * * @param file Path to 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 col If non-NULL, will contain last column parsed (undefined if file could not be opened). - * @return An SMCParseError result code. + * @param states Optional pointer to store last known states. + * @return An SMCError result code. */ - virtual SMCParseError ParseFile_SMC(const char *file, + virtual SMCError ParseFile_SMC(const char *file, ITextListener_SMC *smc_listener, - unsigned int *line, - unsigned int *col) =0; + SMCStates *states) =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. */ - virtual const char *GetSMCErrorString(SMCParseError err) =0; + virtual const char *GetSMCErrorString(SMCError err) =0; public: /** @@ -395,3 +415,4 @@ namespace SourceMod extern SourceMod::ITextParsers *textparsers; #endif //_INCLUDE_SOURCEMOD_TEXTPARSERS_INTERFACE_H_ +