More Windows build fix.
3 * =============================================================================
5 * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
6 * =============================================================================
8 * This program is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, version 3.0, as published by the
10 * Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
20 * As a special exception, AlliedModders LLC gives you permission to link the
21 * code of this program (as well as its derivative works) to "Half-Life 2," the
22 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
23 * by the Valve Corporation. You must obey the GNU General Public License in
24 * all respects for all other code used. Additionally, AlliedModders LLC grants
25 * this exception to all derivative works. AlliedModders LLC defines further
26 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
27 * or <http://www.sourcemod.net/license.php>.
34 #include "GameConfigs.h"
37 #define PSTATE_GAMES 1
38 #define PSTATE_GAMEDEFS 2
39 #define PSTATE_GAMEDEFS_OFFSETS 3
40 #define PSTATE_GAMEDEFS_OFFSETS_OFFSET 4
41 #define PSTATE_GAMEDEFS_KEYS 5
42 #define PSTATE_GAMEDEFS_SUPPORTED 6
43 #define PSTATE_GAMEDEFS_SIGNATURES 7
44 #define PSTATE_GAMEDEFS_SIGNATURES_SIG 8
45 #define PSTATE_GAMEDEFS_CRC 9
46 #define PSTATE_GAMEDEFS_CRC_BINARY 10
47 #define PSTATE_GAMEDEFS_CUSTOM 11
48 #define PSTATE_GAMEDEFS_OPTIONS 12
53 #define PLATFORM_NAME "linux"
54 #define PLATFORM_SERVER_BINARY "server_i486.so"
59 unsigned int s_ServerBinCRC;
60 bool s_ServerBinCRC_Ok = false;
62 bool DoesGameMatch(const char *value)
64 if (strcmp(value, game) == 0)
71 bool DoesEngineMatch(const char *value)
73 if (strcmp(value, engine) == 0)
80 CGameConfig::CGameConfig()
82 m_pStrings = new BaseStringTable(512);
86 m_CustomHandler = NULL;
89 CGameConfig::~CGameConfig()
94 SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *name)
99 return SMCResult_Continue;
102 switch (m_ParseState)
106 if (strcmp(name, "Games") == 0)
108 m_ParseState = PSTATE_GAMES;
116 if (strcmp(name, "*") == 0 ||
117 strcmp(name, "#default") == 0 ||
120 bShouldBeReadingDefault = true;
121 m_ParseState = PSTATE_GAMEDEFS;
122 strncopy(m_Game, name, sizeof(m_Game));
128 case PSTATE_GAMEDEFS:
130 if (strcmp(name, "Offsets") == 0)
132 m_ParseState = PSTATE_GAMEDEFS_OFFSETS;
134 else if (strcmp(name, "Keys") == 0)
136 m_ParseState = PSTATE_GAMEDEFS_KEYS;
138 else if (strcmp(name, "Options") == 0)
140 m_ParseState = PSTATE_GAMEDEFS_OPTIONS;
142 else if ((strcmp(name, "#supported") == 0) && (strcmp(m_Game, "#default") == 0))
144 m_ParseState = PSTATE_GAMEDEFS_SUPPORTED;
145 /* Ignore this section unless we get a game. */
146 bShouldBeReadingDefault = false;
148 matched_game = false;
150 matched_engine = false;
152 else if (strcmp(name, "Signatures") == 0)
154 m_ParseState = PSTATE_GAMEDEFS_SIGNATURES;
163 case PSTATE_GAMEDEFS_OFFSETS:
167 tempOffset = new Offset();
168 tempOffset->setName(name);
169 m_ParseState = PSTATE_GAMEDEFS_OFFSETS_OFFSET;
172 case PSTATE_GAMEDEFS_SIGNATURES:
175 tempSig->setName(name);
176 m_ParseState = PSTATE_GAMEDEFS_SIGNATURES_SIG;
179 /* No sub-sections allowed:
180 case PSTATE_GAMEDEFS_OFFSETS_OFFSET:
181 case PSTATE_GAMEDEFS_KEYS:
182 case PSTATE_GAMEDEFS_SUPPORTED:
183 case PSTATE_GAMEDEFS_SIGNATURES_SIG:
184 case PSTATE_GAMEDEFS_CRC_BINARY:
188 /* If we don't know what we got, start ignoring */
194 return SMCResult_Continue;
197 SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
201 return SMCResult_Continue;
204 if (m_ParseState == PSTATE_GAMEDEFS_OFFSETS_OFFSET)
206 if (strcmp(key, "class") == 0)
208 strncopy(m_Class, value, sizeof(m_Class));
209 } else if (strcmp(key, "prop") == 0) {
210 strncopy(m_Prop, value, sizeof(m_Prop));
212 int val = atoi(value);
213 if (strcmp(key, "windows") == 0) tempOffset->setWin(val);
214 else if (strcmp(key, "linux") == 0) tempOffset->setLin(val);
216 } else if (m_ParseState == PSTATE_GAMEDEFS_KEYS) {
217 m_Keys.replace(key, m_pStrings->AddString(value));
218 } else if (m_ParseState == PSTATE_GAMEDEFS_OPTIONS) {
219 m_Options.replace(key, m_pStrings->AddString(value));
220 } else if (m_ParseState == PSTATE_GAMEDEFS_SUPPORTED) {
221 if (strcmp(key, "game") == 0)
224 if (DoesGameMatch(value))
228 if ((!had_engine && matched_game) || (matched_engine && matched_game))
230 bShouldBeReadingDefault = true;
233 else if (strcmp(key, "engine") == 0)
236 if (DoesEngineMatch(value))
238 matched_engine = true;
240 if ((!had_game && matched_engine) || (matched_game && matched_engine))
242 bShouldBeReadingDefault = true;
245 } else if (m_ParseState == PSTATE_GAMEDEFS_SIGNATURES_SIG) {
246 if (strcmp(key, "windows") == 0) tempSig->setWin(value);
247 else if (strcmp(key, "linux") == 0) tempSig->setLin(value);
248 else if (strcmp(key, "library") == 0) tempSig->setLib(value);
249 } else if (m_ParseState == PSTATE_GAMEDEFS_CRC_BINARY) {
250 if (strcmp(key, PLATFORM_NAME) == 0
252 && !bShouldBeReadingDefault)
254 unsigned int crc = 0;
255 sscanf(value, "%08X", &crc);
256 if (s_ServerBinCRC == crc)
258 bShouldBeReadingDefault = true;
261 } else if (m_ParseState == PSTATE_GAMEDEFS_CUSTOM) {
262 return m_CustomHandler->ReadSMC_KeyValue(states, key, value);
265 return SMCResult_Continue;
268 SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
273 return SMCResult_Continue;
279 m_CustomHandler->ReadSMC_LeavingSection(states);
280 return SMCResult_Continue;
283 switch (m_ParseState)
287 m_ParseState = PSTATE_NONE;
290 case PSTATE_GAMEDEFS:
292 m_ParseState = PSTATE_GAMES;
295 case PSTATE_GAMEDEFS_CUSTOM:
297 m_ParseState = PSTATE_GAMEDEFS;
298 m_CustomHandler->ReadSMC_ParseEnd(false, false);
301 case PSTATE_GAMEDEFS_KEYS:
302 case PSTATE_GAMEDEFS_OFFSETS:
303 case PSTATE_GAMEDEFS_OPTIONS:
305 m_ParseState = PSTATE_GAMEDEFS;
308 case PSTATE_GAMEDEFS_OFFSETS_OFFSET:
310 for (list<Offset>::iterator it = m_Offsets.begin(); it != m_Offsets.end(); it++)
312 if (strcmp(it->name, tempOffset->name) == 0)
318 m_Offsets.push_back(*tempOffset);
319 m_ParseState = PSTATE_GAMEDEFS_OFFSETS;
322 case PSTATE_GAMEDEFS_CRC:
323 case PSTATE_GAMEDEFS_SUPPORTED:
325 if (!bShouldBeReadingDefault)
327 /* If we shouldn't read the rest of this section, set the ignore level. */
329 m_ParseState = PSTATE_GAMES;
331 m_ParseState = PSTATE_GAMEDEFS;
335 case PSTATE_GAMEDEFS_CRC_BINARY:
337 m_ParseState = PSTATE_GAMEDEFS_CRC;
340 case PSTATE_GAMEDEFS_SIGNATURES:
342 m_ParseState = PSTATE_GAMEDEFS;
345 case PSTATE_GAMEDEFS_SIGNATURES_SIG:
347 m_Sigs.push_back(*tempSig);
348 m_ParseState = PSTATE_GAMEDEFS_SIGNATURES;
354 return SMCResult_Continue;
357 #define MSTATE_NONE 0
358 #define MSTATE_MAIN 1
359 #define MSTATE_FILE 2
361 class MasterReader : public ITextListener_SMC
364 virtual void ReadSMC_ParseStart()
370 virtual SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name)
374 return SMCResult_Continue;
377 if (state == MSTATE_NONE)
379 if (strcmp(name, "Game Master") == 0)
388 else if (state == MSTATE_MAIN)
390 strncopy(cur_file, name, sizeof(cur_file));
392 matched_engine = false;
394 matched_game = false;
397 else if (state == MSTATE_FILE)
402 return SMCResult_Continue;
405 virtual SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
407 if (ignoreLevel || state != MSTATE_FILE)
409 return SMCResult_Continue;
412 if (strcmp(key, "engine") == 0)
415 if (DoesEngineMatch(value))
417 matched_engine = true;
420 else if (strcmp(key, "game") == 0)
423 if (DoesGameMatch(value))
429 return SMCResult_Continue;
432 virtual SMCResult ReadSMC_LeavingSection(const SMCStates *states)
437 return SMCResult_Continue;
440 if (state == MSTATE_FILE)
442 /* The four success conditions:
444 * 2. Needed game only.
445 * 3. Needed engine only.
446 * 4. Needed both engine and game.
447 * Final result is minimized via k-map.
450 if ((!had_engine && !had_game) ||
451 (!had_engine && matched_game) ||
452 (!had_game && matched_engine) ||
453 (matched_engine && matched_game))
455 fileList->push_back(cur_file);
459 else if (state == MSTATE_MAIN)
464 return SMCResult_Continue;
467 list<char*> *fileList;
469 unsigned int ignoreLevel;
470 char cur_file[PLATFORM_MAX_PATH];
477 static MasterReader master_reader;
479 bool CGameConfig::Reparse(char *error, size_t maxlength)
481 /* Reset cached data */
488 char path[PLATFORM_MAX_PATH];
490 /* See if we can use the extended gamedata format. */
491 //TODO pass in path to gamedata somehow
493 /* Otherwise, it's time to parse the master. */
495 SMCStates state = {0, 0};
496 list<char*> fileList;
497 master_reader.fileList = &fileList;
499 err = textparsers->ParseSMCFile(path, &master_reader, &state, error, maxlength);
500 if (err != SMCError_Okay)
502 const char *msg = textparsers->GetSMCErrorString(err);
504 printf("[SM] Error parsing master gameconf file \"%s\":", path);
505 printf("[SM] Error %d on line %d, col %d: %s",
509 msg ? msg : "Unknown error");
513 /* Go through each file we found and parse it. */
514 list<char*>::iterator iter;
515 for (iter = fileList.begin(); iter != fileList.end(); iter++)
517 UTIL_Format(path, sizeof(path), "%s/%s", m_File, *iter);
518 if (!EnterFile(path, error, maxlength))
527 bool CGameConfig::EnterFile(const char *file, char *error, size_t maxlength)
530 SMCStates state = {0, 0};
532 /* Initialize parse states */
534 bShouldBeReadingDefault = true;
535 m_ParseState = PSTATE_NONE;
537 if ((err=textparsers->ParseSMCFile(file, this, &state, error, maxlength))
542 msg = textparsers->GetSMCErrorString(err);
544 printf("[SM] Error parsing gameconfig file \"%s\":\n", file);
545 printf("[SM] Error %d on line %d, col %d: %s\n",
549 msg ? msg : "Unknown error");
551 if (m_ParseState == PSTATE_GAMEDEFS_CUSTOM)
553 //error occurred while parsing a custom section
554 m_CustomHandler->ReadSMC_ParseEnd(true, true);
555 m_CustomHandler = NULL;
565 const char *CGameConfig::GetKeyValue(const char *key)
568 if ((pkey = m_Keys.retrieve(key)) == NULL)
570 return m_pStrings->GetString(*pkey);
573 const char *CGameConfig::GetOptionValue(const char *key)
576 if ((pkey = m_Options.retrieve(key)) == NULL)
578 return m_pStrings->GetString(*pkey);
581 list<Offset> CGameConfig::GetOffsets() { return m_Offsets; }
582 list<Sig> CGameConfig::GetSigs() { return m_Sigs; }