skamonkey@3513: /** skamonkey@3513: * vim: set ts=4 : skamonkey@3513: * ============================================================================= skamonkey@3513: * SourceMod skamonkey@3513: * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. skamonkey@3513: * ============================================================================= skamonkey@3513: * skamonkey@3513: * This program is free software; you can redistribute it and/or modify it under skamonkey@3513: * the terms of the GNU General Public License, version 3.0, as published by the skamonkey@3513: * Free Software Foundation. skamonkey@3513: * skamonkey@3513: * This program is distributed in the hope that it will be useful, but WITHOUT skamonkey@3513: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS skamonkey@3513: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more skamonkey@3513: * details. skamonkey@3513: * skamonkey@3513: * You should have received a copy of the GNU General Public License along with skamonkey@3513: * this program. If not, see . skamonkey@3513: * skamonkey@3513: * As a special exception, AlliedModders LLC gives you permission to link the skamonkey@3513: * code of this program (as well as its derivative works) to "Half-Life 2," the skamonkey@3513: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software skamonkey@3513: * by the Valve Corporation. You must obey the GNU General Public License in skamonkey@3513: * all respects for all other code used. Additionally, AlliedModders LLC grants skamonkey@3513: * this exception to all derivative works. AlliedModders LLC defines further skamonkey@3513: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), skamonkey@3513: * or . skamonkey@3513: * skamonkey@3513: * Version: $Id$ skamonkey@3513: */ skamonkey@3513: skamonkey@3513: #include skamonkey@3513: #include skamonkey@3513: #include "GameConfigs.h" skamonkey@3513: skamonkey@3513: #define PSTATE_NONE 0 skamonkey@3513: #define PSTATE_GAMES 1 skamonkey@3513: #define PSTATE_GAMEDEFS 2 skamonkey@3513: #define PSTATE_GAMEDEFS_OFFSETS 3 skamonkey@3513: #define PSTATE_GAMEDEFS_OFFSETS_OFFSET 4 skamonkey@3513: #define PSTATE_GAMEDEFS_KEYS 5 skamonkey@3513: #define PSTATE_GAMEDEFS_SUPPORTED 6 skamonkey@3513: #define PSTATE_GAMEDEFS_SIGNATURES 7 skamonkey@3513: #define PSTATE_GAMEDEFS_SIGNATURES_SIG 8 skamonkey@3513: #define PSTATE_GAMEDEFS_CRC 9 skamonkey@3513: #define PSTATE_GAMEDEFS_CRC_BINARY 10 skamonkey@3513: #define PSTATE_GAMEDEFS_CUSTOM 11 skamonkey@3574: #define PSTATE_GAMEDEFS_OPTIONS 12 skamonkey@3513: skamonkey@3513: #define WIN 0 skamonkey@3513: #define LIN 1 skamonkey@3513: skamonkey@3513: #define PLATFORM_NAME "linux" skamonkey@3513: #define PLATFORM_SERVER_BINARY "server_i486.so" skamonkey@3513: skamonkey@3513: Offset *tempOffset; skamonkey@3513: Sig *tempSig; skamonkey@3513: skamonkey@3513: unsigned int s_ServerBinCRC; skamonkey@3513: bool s_ServerBinCRC_Ok = false; skamonkey@3513: skamonkey@3513: bool DoesGameMatch(const char *value) skamonkey@3513: { skamonkey@3513: if (strcmp(value, game) == 0) skamonkey@3513: { skamonkey@3513: return true; skamonkey@3513: } skamonkey@3513: return false; skamonkey@3513: } skamonkey@3513: skamonkey@3513: bool DoesEngineMatch(const char *value) skamonkey@3513: { skamonkey@3513: if (strcmp(value, engine) == 0) skamonkey@3513: { skamonkey@3513: return true; skamonkey@3513: } skamonkey@3513: return false; skamonkey@3513: } skamonkey@3513: skamonkey@3513: CGameConfig::CGameConfig() skamonkey@3513: { skamonkey@3513: m_pStrings = new BaseStringTable(512); skamonkey@3513: m_RefCount = 0; skamonkey@3513: skamonkey@3513: m_CustomLevel = 0; skamonkey@3513: m_CustomHandler = NULL; skamonkey@3513: } skamonkey@3513: skamonkey@3513: CGameConfig::~CGameConfig() skamonkey@3513: { skamonkey@3513: delete m_pStrings; skamonkey@3513: } skamonkey@3513: skamonkey@3513: SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *name) skamonkey@3513: { skamonkey@3513: if (m_IgnoreLevel) skamonkey@3513: { skamonkey@3513: m_IgnoreLevel++; skamonkey@3513: return SMCResult_Continue; skamonkey@3513: } skamonkey@3513: skamonkey@3513: switch (m_ParseState) skamonkey@3513: { skamonkey@3513: case PSTATE_NONE: skamonkey@3513: { skamonkey@3513: if (strcmp(name, "Games") == 0) skamonkey@3513: { skamonkey@3513: m_ParseState = PSTATE_GAMES; skamonkey@3513: } else { skamonkey@3513: m_IgnoreLevel++; skamonkey@3513: } skamonkey@3513: break; skamonkey@3513: } skamonkey@3513: case PSTATE_GAMES: skamonkey@3513: { skamonkey@3513: if (strcmp(name, "*") == 0 || skamonkey@3513: strcmp(name, "#default") == 0 || skamonkey@3513: DoesGameMatch(name)) skamonkey@3513: { skamonkey@3513: bShouldBeReadingDefault = true; skamonkey@3513: m_ParseState = PSTATE_GAMEDEFS; skamonkey@3513: strncopy(m_Game, name, sizeof(m_Game)); skamonkey@3513: } else { skamonkey@3513: m_IgnoreLevel++; skamonkey@3513: } skamonkey@3513: break; skamonkey@3513: } skamonkey@3513: case PSTATE_GAMEDEFS: skamonkey@3513: { skamonkey@3513: if (strcmp(name, "Offsets") == 0) skamonkey@3513: { skamonkey@3513: m_ParseState = PSTATE_GAMEDEFS_OFFSETS; skamonkey@3513: } skamonkey@3513: else if (strcmp(name, "Keys") == 0) skamonkey@3513: { skamonkey@3513: m_ParseState = PSTATE_GAMEDEFS_KEYS; skamonkey@3513: } skamonkey@3574: else if (strcmp(name, "Options") == 0) skamonkey@3574: { skamonkey@3574: m_ParseState = PSTATE_GAMEDEFS_OPTIONS; skamonkey@3574: } skamonkey@3513: else if ((strcmp(name, "#supported") == 0) && (strcmp(m_Game, "#default") == 0)) skamonkey@3513: { skamonkey@3513: m_ParseState = PSTATE_GAMEDEFS_SUPPORTED; skamonkey@3513: /* Ignore this section unless we get a game. */ skamonkey@3513: bShouldBeReadingDefault = false; skamonkey@3513: had_game = false; skamonkey@3513: matched_game = false; skamonkey@3513: had_engine = false; skamonkey@3513: matched_engine = false; skamonkey@3513: } skamonkey@3513: else if (strcmp(name, "Signatures") == 0) skamonkey@3513: { skamonkey@3513: m_ParseState = PSTATE_GAMEDEFS_SIGNATURES; skamonkey@3513: } skamonkey@3694: else skamonkey@3694: { skamonkey@3694: m_IgnoreLevel++; skamonkey@3694: } skamonkey@3513: skamonkey@3513: break; skamonkey@3513: } skamonkey@3513: case PSTATE_GAMEDEFS_OFFSETS: skamonkey@3513: { skamonkey@3513: m_Prop[0] = '\0'; skamonkey@3513: m_Class[0] = '\0'; skamonkey@3513: tempOffset = new Offset(); skamonkey@3513: tempOffset->setName(name); skamonkey@3513: m_ParseState = PSTATE_GAMEDEFS_OFFSETS_OFFSET; skamonkey@3513: break; skamonkey@3513: } skamonkey@3513: case PSTATE_GAMEDEFS_SIGNATURES: skamonkey@3513: { skamonkey@3513: tempSig = new Sig(); skamonkey@3513: tempSig->setName(name); skamonkey@3513: m_ParseState = PSTATE_GAMEDEFS_SIGNATURES_SIG; skamonkey@3513: break; skamonkey@3513: } skamonkey@3513: /* No sub-sections allowed: skamonkey@3513: case PSTATE_GAMEDEFS_OFFSETS_OFFSET: skamonkey@3513: case PSTATE_GAMEDEFS_KEYS: skamonkey@3513: case PSTATE_GAMEDEFS_SUPPORTED: skamonkey@3513: case PSTATE_GAMEDEFS_SIGNATURES_SIG: skamonkey@3513: case PSTATE_GAMEDEFS_CRC_BINARY: skamonkey@3513: */ skamonkey@3513: default: skamonkey@3513: { skamonkey@3513: /* If we don't know what we got, start ignoring */ skamonkey@3513: m_IgnoreLevel++; skamonkey@3513: break; skamonkey@3513: } skamonkey@3513: } skamonkey@3513: skamonkey@3513: return SMCResult_Continue; skamonkey@3513: } skamonkey@3513: skamonkey@3513: SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value) skamonkey@3513: { skamonkey@3513: if (m_IgnoreLevel) skamonkey@3513: { skamonkey@3513: return SMCResult_Continue; skamonkey@3513: } skamonkey@3513: skamonkey@3513: if (m_ParseState == PSTATE_GAMEDEFS_OFFSETS_OFFSET) skamonkey@3513: { skamonkey@3513: if (strcmp(key, "class") == 0) skamonkey@3513: { skamonkey@3513: strncopy(m_Class, value, sizeof(m_Class)); skamonkey@3513: } else if (strcmp(key, "prop") == 0) { skamonkey@3513: strncopy(m_Prop, value, sizeof(m_Prop)); skamonkey@3513: } else { skamonkey@3513: int val = atoi(value); skamonkey@3513: if (strcmp(key, "windows") == 0) tempOffset->setWin(val); skamonkey@3513: else if (strcmp(key, "linux") == 0) tempOffset->setLin(val); skamonkey@3513: } skamonkey@3513: } else if (m_ParseState == PSTATE_GAMEDEFS_KEYS) { skamonkey@3513: m_Keys.replace(key, m_pStrings->AddString(value)); skamonkey@3574: } else if (m_ParseState == PSTATE_GAMEDEFS_OPTIONS) { skamonkey@3574: m_Options.replace(key, m_pStrings->AddString(value)); skamonkey@3513: } else if (m_ParseState == PSTATE_GAMEDEFS_SUPPORTED) { skamonkey@3513: if (strcmp(key, "game") == 0) skamonkey@3513: { skamonkey@3513: had_game = true; skamonkey@3513: if (DoesGameMatch(value)) skamonkey@3513: { skamonkey@3513: matched_game = true; skamonkey@3513: } skamonkey@3513: if ((!had_engine && matched_game) || (matched_engine && matched_game)) skamonkey@3513: { skamonkey@3513: bShouldBeReadingDefault = true; skamonkey@3513: } skamonkey@3513: } skamonkey@3513: else if (strcmp(key, "engine") == 0) skamonkey@3513: { skamonkey@3513: had_engine = true; skamonkey@3513: if (DoesEngineMatch(value)) skamonkey@3513: { skamonkey@3513: matched_engine = true; skamonkey@3513: } skamonkey@3513: if ((!had_game && matched_engine) || (matched_game && matched_engine)) skamonkey@3513: { skamonkey@3513: bShouldBeReadingDefault = true; skamonkey@3513: } skamonkey@3513: } skamonkey@3513: } else if (m_ParseState == PSTATE_GAMEDEFS_SIGNATURES_SIG) { skamonkey@3513: if (strcmp(key, "windows") == 0) tempSig->setWin(value); skamonkey@3513: else if (strcmp(key, "linux") == 0) tempSig->setLin(value); skamonkey@3513: else if (strcmp(key, "library") == 0) tempSig->setLib(value); skamonkey@3513: } else if (m_ParseState == PSTATE_GAMEDEFS_CRC_BINARY) { skamonkey@3513: if (strcmp(key, PLATFORM_NAME) == 0 skamonkey@3513: && s_ServerBinCRC_Ok skamonkey@3513: && !bShouldBeReadingDefault) skamonkey@3513: { skamonkey@3513: unsigned int crc = 0; skamonkey@3513: sscanf(value, "%08X", &crc); skamonkey@3513: if (s_ServerBinCRC == crc) skamonkey@3513: { skamonkey@3513: bShouldBeReadingDefault = true; skamonkey@3513: } skamonkey@3513: } skamonkey@3513: } else if (m_ParseState == PSTATE_GAMEDEFS_CUSTOM) { skamonkey@3513: return m_CustomHandler->ReadSMC_KeyValue(states, key, value); skamonkey@3513: } skamonkey@3513: skamonkey@3513: return SMCResult_Continue; skamonkey@3513: } skamonkey@3513: skamonkey@3513: SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states) skamonkey@3513: { skamonkey@3513: if (m_IgnoreLevel) skamonkey@3513: { skamonkey@3513: m_IgnoreLevel--; skamonkey@3513: return SMCResult_Continue; skamonkey@3513: } skamonkey@3513: skamonkey@3513: if (m_CustomLevel) skamonkey@3513: { skamonkey@3513: m_CustomLevel--; skamonkey@3513: m_CustomHandler->ReadSMC_LeavingSection(states); skamonkey@3513: return SMCResult_Continue; skamonkey@3513: } skamonkey@3513: skamonkey@3513: switch (m_ParseState) skamonkey@3513: { skamonkey@3513: case PSTATE_GAMES: skamonkey@3513: { skamonkey@3513: m_ParseState = PSTATE_NONE; skamonkey@3513: break; skamonkey@3513: } skamonkey@3513: case PSTATE_GAMEDEFS: skamonkey@3513: { skamonkey@3513: m_ParseState = PSTATE_GAMES; skamonkey@3513: break; skamonkey@3513: } skamonkey@3513: case PSTATE_GAMEDEFS_CUSTOM: skamonkey@3513: { skamonkey@3513: m_ParseState = PSTATE_GAMEDEFS; skamonkey@3513: m_CustomHandler->ReadSMC_ParseEnd(false, false); skamonkey@3513: break; skamonkey@3513: } skamonkey@3513: case PSTATE_GAMEDEFS_KEYS: skamonkey@3513: case PSTATE_GAMEDEFS_OFFSETS: skamonkey@3574: case PSTATE_GAMEDEFS_OPTIONS: skamonkey@3513: { skamonkey@3513: m_ParseState = PSTATE_GAMEDEFS; skamonkey@3513: break; skamonkey@3513: } skamonkey@3513: case PSTATE_GAMEDEFS_OFFSETS_OFFSET: skamonkey@3513: { skamonkey@3513: for (list::iterator it = m_Offsets.begin(); it != m_Offsets.end(); it++) skamonkey@3513: { skamonkey@3513: if (strcmp(it->name, tempOffset->name) == 0) skamonkey@3513: { skamonkey@3513: m_Offsets.erase(it); skamonkey@3513: break; skamonkey@3513: } skamonkey@3513: } skamonkey@3513: m_Offsets.push_back(*tempOffset); skamonkey@3513: m_ParseState = PSTATE_GAMEDEFS_OFFSETS; skamonkey@3513: break; skamonkey@3513: } skamonkey@3513: case PSTATE_GAMEDEFS_CRC: skamonkey@3513: case PSTATE_GAMEDEFS_SUPPORTED: skamonkey@3513: { skamonkey@3513: if (!bShouldBeReadingDefault) skamonkey@3513: { skamonkey@3513: /* If we shouldn't read the rest of this section, set the ignore level. */ skamonkey@3513: m_IgnoreLevel = 1; skamonkey@3513: m_ParseState = PSTATE_GAMES; skamonkey@3513: } else { skamonkey@3513: m_ParseState = PSTATE_GAMEDEFS; skamonkey@3513: } skamonkey@3513: break; skamonkey@3513: } skamonkey@3513: case PSTATE_GAMEDEFS_CRC_BINARY: skamonkey@3513: { skamonkey@3513: m_ParseState = PSTATE_GAMEDEFS_CRC; skamonkey@3513: break; skamonkey@3513: } skamonkey@3513: case PSTATE_GAMEDEFS_SIGNATURES: skamonkey@3513: { skamonkey@3513: m_ParseState = PSTATE_GAMEDEFS; skamonkey@3513: break; skamonkey@3513: } skamonkey@3513: case PSTATE_GAMEDEFS_SIGNATURES_SIG: skamonkey@3513: { skamonkey@3513: m_Sigs.push_back(*tempSig); skamonkey@3513: m_ParseState = PSTATE_GAMEDEFS_SIGNATURES; skamonkey@3513: skamonkey@3513: break; skamonkey@3513: } skamonkey@3513: } skamonkey@3513: skamonkey@3513: return SMCResult_Continue; skamonkey@3513: } skamonkey@3513: skamonkey@3513: #define MSTATE_NONE 0 skamonkey@3513: #define MSTATE_MAIN 1 skamonkey@3513: #define MSTATE_FILE 2 skamonkey@3513: skamonkey@3513: class MasterReader : public ITextListener_SMC skamonkey@3513: { skamonkey@3513: public: skamonkey@3513: virtual void ReadSMC_ParseStart() skamonkey@3513: { skamonkey@3513: state = MSTATE_NONE; skamonkey@3513: ignoreLevel = 0; skamonkey@3513: } skamonkey@3513: skamonkey@3513: virtual SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name) skamonkey@3513: { skamonkey@3513: if (ignoreLevel) skamonkey@3513: { skamonkey@3513: return SMCResult_Continue; skamonkey@3513: } skamonkey@3513: skamonkey@3513: if (state == MSTATE_NONE) skamonkey@3513: { skamonkey@3513: if (strcmp(name, "Game Master") == 0) skamonkey@3513: { skamonkey@3513: state = MSTATE_MAIN; skamonkey@3513: } skamonkey@3513: else skamonkey@3513: { skamonkey@3513: ignoreLevel++; skamonkey@3513: } skamonkey@3513: } skamonkey@3513: else if (state == MSTATE_MAIN) skamonkey@3513: { skamonkey@3513: strncopy(cur_file, name, sizeof(cur_file)); skamonkey@3513: had_engine = false; skamonkey@3513: matched_engine = false; skamonkey@3513: had_game = false; skamonkey@3513: matched_game = false; skamonkey@3513: state = MSTATE_FILE; skamonkey@3513: } skamonkey@3513: else if (state == MSTATE_FILE) skamonkey@3513: { skamonkey@3513: ignoreLevel++; skamonkey@3513: } skamonkey@3513: skamonkey@3513: return SMCResult_Continue; skamonkey@3513: } skamonkey@3513: skamonkey@3513: virtual SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value) skamonkey@3513: { skamonkey@3513: if (ignoreLevel || state != MSTATE_FILE) skamonkey@3513: { skamonkey@3513: return SMCResult_Continue; skamonkey@3513: } skamonkey@3513: skamonkey@3513: if (strcmp(key, "engine") == 0) skamonkey@3513: { skamonkey@3513: had_engine = true; skamonkey@3513: if (DoesEngineMatch(value)) skamonkey@3513: { skamonkey@3513: matched_engine = true; skamonkey@3513: } skamonkey@3513: } skamonkey@3513: else if (strcmp(key, "game") == 0) skamonkey@3513: { skamonkey@3513: had_game = true; skamonkey@3513: if (DoesGameMatch(value)) skamonkey@3513: { skamonkey@3513: matched_game = true; skamonkey@3513: } skamonkey@3513: } skamonkey@3513: skamonkey@3513: return SMCResult_Continue; skamonkey@3513: } skamonkey@3513: skamonkey@3513: virtual SMCResult ReadSMC_LeavingSection(const SMCStates *states) skamonkey@3513: { skamonkey@3513: if (ignoreLevel) skamonkey@3513: { skamonkey@3513: ignoreLevel--; skamonkey@3513: return SMCResult_Continue; skamonkey@3513: } skamonkey@3513: skamonkey@3513: if (state == MSTATE_FILE) skamonkey@3513: { skamonkey@3513: /* The four success conditions: skamonkey@3513: * 1. Needed nothing. skamonkey@3513: * 2. Needed game only. skamonkey@3513: * 3. Needed engine only. skamonkey@3513: * 4. Needed both engine and game. skamonkey@3513: * Final result is minimized via k-map. skamonkey@3513: */ skamonkey@3513: skamonkey@3513: if ((!had_engine && !had_game) || skamonkey@3513: (!had_engine && matched_game) || skamonkey@3513: (!had_game && matched_engine) || skamonkey@3513: (matched_engine && matched_game)) skamonkey@3513: { skamonkey@3513: fileList->push_back(cur_file); skamonkey@3513: } skamonkey@3513: state = MSTATE_MAIN; skamonkey@3513: } skamonkey@3513: else if (state == MSTATE_MAIN) skamonkey@3513: { skamonkey@3513: state = MSTATE_NONE; skamonkey@3513: } skamonkey@3513: skamonkey@3513: return SMCResult_Continue; skamonkey@3513: } skamonkey@3513: public: skamonkey@3513: list *fileList; skamonkey@3513: unsigned int state; skamonkey@3513: unsigned int ignoreLevel; skamonkey@3513: char cur_file[PLATFORM_MAX_PATH]; skamonkey@3513: bool had_engine; skamonkey@3513: bool matched_engine; skamonkey@3513: bool had_game; skamonkey@3513: bool matched_game; skamonkey@3513: }; skamonkey@3513: skamonkey@3513: static MasterReader master_reader; skamonkey@3513: skamonkey@3513: bool CGameConfig::Reparse(char *error, size_t maxlength) skamonkey@3513: { skamonkey@3513: /* Reset cached data */ skamonkey@3513: m_pStrings->Reset(); skamonkey@3513: m_Offsets.clear(); skamonkey@3513: m_Sigs.clear(); skamonkey@3513: m_Keys.clear(); skamonkey@3574: m_Options.clear(); skamonkey@3513: skamonkey@3513: char path[PLATFORM_MAX_PATH]; skamonkey@3513: skamonkey@3513: /* See if we can use the extended gamedata format. */ skamonkey@3513: //TODO pass in path to gamedata somehow skamonkey@3513: skamonkey@3513: /* Otherwise, it's time to parse the master. */ skamonkey@3513: SMCError err; skamonkey@3513: SMCStates state = {0, 0}; skamonkey@3513: list fileList; skamonkey@3513: master_reader.fileList = &fileList; skamonkey@3513: skamonkey@3513: err = textparsers->ParseSMCFile(path, &master_reader, &state, error, maxlength); skamonkey@3513: if (err != SMCError_Okay) skamonkey@3513: { skamonkey@3513: const char *msg = textparsers->GetSMCErrorString(err); skamonkey@3513: skamonkey@3513: printf("[SM] Error parsing master gameconf file \"%s\":", path); skamonkey@3513: printf("[SM] Error %d on line %d, col %d: %s", skamonkey@3513: err, skamonkey@3513: state.line, skamonkey@3513: state.col, skamonkey@3513: msg ? msg : "Unknown error"); skamonkey@3513: exit(PARSE_ERROR); skamonkey@3513: } skamonkey@3513: skamonkey@3513: /* Go through each file we found and parse it. */ skamonkey@3513: list::iterator iter; skamonkey@3513: for (iter = fileList.begin(); iter != fileList.end(); iter++) skamonkey@3513: { skamonkey@3513: UTIL_Format(path, sizeof(path), "%s/%s", m_File, *iter); skamonkey@3513: if (!EnterFile(path, error, maxlength)) skamonkey@3513: { skamonkey@3513: return false; skamonkey@3513: } skamonkey@3513: } skamonkey@3513: skamonkey@3513: return true; skamonkey@3513: } skamonkey@3513: skamonkey@3513: bool CGameConfig::EnterFile(const char *file, char *error, size_t maxlength) skamonkey@3513: { skamonkey@3513: SMCError err; skamonkey@3513: SMCStates state = {0, 0}; skamonkey@3513: skamonkey@3513: /* Initialize parse states */ skamonkey@3513: m_IgnoreLevel = 0; skamonkey@3513: bShouldBeReadingDefault = true; skamonkey@3513: m_ParseState = PSTATE_NONE; skamonkey@3513: skamonkey@3513: if ((err=textparsers->ParseSMCFile(file, this, &state, error, maxlength)) skamonkey@3513: != SMCError_Okay) skamonkey@3513: { skamonkey@3513: const char *msg; skamonkey@3513: skamonkey@3513: msg = textparsers->GetSMCErrorString(err); skamonkey@3513: skamonkey@3513: printf("[SM] Error parsing gameconfig file \"%s\":\n", file); skamonkey@3513: printf("[SM] Error %d on line %d, col %d: %s\n", skamonkey@3513: err, skamonkey@3513: state.line, skamonkey@3513: state.col, skamonkey@3513: msg ? msg : "Unknown error"); skamonkey@3513: skamonkey@3513: if (m_ParseState == PSTATE_GAMEDEFS_CUSTOM) skamonkey@3513: { skamonkey@3513: //error occurred while parsing a custom section skamonkey@3513: m_CustomHandler->ReadSMC_ParseEnd(true, true); skamonkey@3513: m_CustomHandler = NULL; skamonkey@3513: m_CustomLevel = 0; skamonkey@3513: } skamonkey@3513: skamonkey@3513: exit(PARSE_ERROR); skamonkey@3513: } skamonkey@3513: skamonkey@3513: return true; skamonkey@3513: } skamonkey@3513: skamonkey@3513: const char *CGameConfig::GetKeyValue(const char *key) skamonkey@3513: { skamonkey@3513: int *pkey; skamonkey@3513: if ((pkey = m_Keys.retrieve(key)) == NULL) skamonkey@3513: return NULL; skamonkey@3513: return m_pStrings->GetString(*pkey); skamonkey@3513: } skamonkey@3513: skamonkey@3574: const char *CGameConfig::GetOptionValue(const char *key) skamonkey@3574: { skamonkey@3574: int *pkey; skamonkey@3574: if ((pkey = m_Options.retrieve(key)) == NULL) skamonkey@3574: return NULL; skamonkey@3574: return m_pStrings->GetString(*pkey); skamonkey@3574: } skamonkey@3574: skamonkey@3513: list CGameConfig::GetOffsets() { return m_Offsets; } skamonkey@3513: list CGameConfig::GetSigs() { return m_Sigs; } skamonkey@3513: