[Menus]: Add two new directives (#747)

This commit is contained in:
Edo 2023-02-01 10:10:24 +00:00 committed by GitHub
parent 43906f4fc0
commit a468cdfae9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 437 additions and 72 deletions

View File

@ -53,6 +53,8 @@
#include "Modules/Vote.hpp" #include "Modules/Vote.hpp"
#include "Modules/Weapon.hpp" #include "Modules/Weapon.hpp"
#include "Modules/BotLib/lPrecomp.hpp"
namespace Components namespace Components
{ {
bool Loader::Pregame = true; bool Loader::Pregame = true;
@ -168,6 +170,8 @@ namespace Components
Register(new GSC()); Register(new GSC());
Register(new lPrecomp());
Pregame = false; Pregame = false;
// Make sure preDestroy is called when the game shuts down // Make sure preDestroy is called when the game shuts down

View File

@ -264,9 +264,9 @@ namespace Assets
AssertSize(Game::Font_s, 24); AssertSize(Game::Font_s, 24);
AssertSize(Game::Glyph, 24); AssertSize(Game::Glyph, 24);
Utils::Stream* buffer = builder->getBuffer(); auto* buffer = builder->getBuffer();
Game::Font_s* asset = header.font; auto* asset = header.font;
Game::Font_s* dest = buffer->dest<Game::Font_s>(); auto* dest = buffer->dest<Game::Font_s>();
buffer->save(asset); buffer->save(asset);

View File

@ -0,0 +1,155 @@
#include <STDInclude.hpp>
#include "lPrecomp.hpp"
namespace Components
{
// Two new directives! Refer to (https://en.cppreference.com/w/cpp/preprocessor/conditional)
Game::directive_s lPrecomp::directives[] =
{
{"if", Game::PC_Directive_if},
{"ifdef", Game::PC_Directive_ifdef},
{"ifndef", Game::PC_Directive_ifndef},
{"elifdef", lPrecomp::PC_Directive_elifdef},
{"elifndef", lPrecomp::PC_Directive_elifndef},
{"elif", Game::PC_Directive_elif},
{"else", Game::PC_Directive_else},
{"endif", Game::PC_Directive_endif},
{"include", Game::PC_Directive_include},
{"define", Game::PC_Directive_define},
{"undef", Game::PC_Directive_undef},
{"line", Game::PC_Directive_line},
{"error", Game::PC_Directive_error},
{"pragma", Game::PC_Directive_pragma},
{"eval", Game::PC_Directive_eval},
{"evalfloat", Game::PC_Directive_evalfloat},
{nullptr, nullptr}
};
int lPrecomp::PC_Directive_elif_def(Game::source_s* source, int* value, int type)
{
Game::token_s token;
int skip;
if (!Game::PC_ReadLine(source, &token, false))
{
Game::SourceError(source, "#elifdef without name");
return false;
}
if (token.type != TT_NAME)
{
Game::PC_UnreadSourceToken(source, &token);
Game::SourceError(source, "expected name after #elifdef, found %s", token.string);
return false;
}
auto* d = Game::PC_FindHashedDefine(source->definehash, token.string);
*value = skip = (type == INDENT_IFDEF) == (d == nullptr);
return true;
}
// #elifdef identifier is essentially equivalent to #elif defined identifier
int lPrecomp::PC_Directive_elifdef(Game::source_s* source)
{
int type;
int skip;
Game::PC_PopIndent(source, &type, &skip);
if (!type || type == INDENT_ELSE)
{
Game::SourceError(source, "misplaced #elifdef");
return false;
}
int value;
if (PC_Directive_elif_def(source, &value, INDENT_IFDEF))
{
if (skip == Game::SKIP_YES)
{
skip = value;
}
else
{
skip = Game::SKIP_ALL_ELIFS;
}
Game::PC_PushIndent(source, INDENT_ELIF, skip);
return true;
}
return false;
}
// #elifndef identifier is essentially equivalent to #elif !defined identifier
int lPrecomp::PC_Directive_elifndef(Game::source_s* source)
{
int type;
int skip;
Game::PC_PopIndent(source, &type, &skip);
if (!type || type == INDENT_ELSE)
{
Game::SourceError(source, "misplaced #elifndef");
return false;
}
int value;
if (PC_Directive_elif_def(source, &value, INDENT_IFNDEF))
{
if (skip == Game::SKIP_YES)
{
skip = value;
}
else
{
skip = Game::SKIP_ALL_ELIFS;
}
Game::PC_PushIndent(source, INDENT_ELIF, skip);
return true;
}
return false;
}
int lPrecomp::PC_ReadDirective(Game::source_s* source)
{
Game::token_s token;
// Read the directive name
if (!Game::PC_ReadSourceToken(source, &token))
{
Game::SourceError(source, "found # without name");
return false;
}
// Directive name must be on the same line
if (token.linescrossed > 0)
{
Game::PC_UnreadSourceToken(source, &token);
Game::SourceError(source, "found # at end of line");
return false;
}
// If it is a name
if (token.type == TT_NAME)
{
// Find the precompiler directive
for (auto i = 0; directives[i].name; ++i)
{
if (!std::strcmp(directives[i].name, token.string))
{
return directives[i].func(source);
}
}
}
Game::SourceError(source, "unknown precompiler directive %s", token.string);
return false;
}
lPrecomp::lPrecomp()
{
Utils::Hook(0x4ACD19, PC_ReadDirective, HOOK_CALL).install()->quick();
}
}

View File

@ -0,0 +1,46 @@
#pragma once
namespace Components
{
class lPrecomp : public Component
{
public:
lPrecomp();
private:
enum
{
INDENT_IF = 1,
INDENT_ELSE = 2,
INDENT_ELIF = 4,
INDENT_IFDEF = 8,
INDENT_IFNDEF = 10,
};
enum
{
TT_STRING = 1,
TT_LITERAL = 2,
TT_NUMBER = 3,
TT_NAME = 4,
TT_PUNCTUATION = 5,
TT_DECIMAL = 8,
TT_HEX = 0x100,
TT_OCTAL = 0x200,
TT_BINARY = 0x400,
TT_FLOAT = 0x800,
TT_INTEGER = 0x1000,
TT_LONG = 0x2000,
TT_UNSIGNED = 0x4000,
};
static Game::directive_s directives[];
static int PC_Directive_elif_def(Game::source_s* source, int* value, int type);
static int PC_Directive_elifdef(Game::source_s* source);
static int PC_Directive_elifndef(Game::source_s* source);
static int PC_ReadDirective(Game::source_s* source);
};
}

View File

@ -55,14 +55,14 @@ namespace Components
} }
// Reserve it, if yes // Reserve it, if yes
Game::sourceFiles[i] = reinterpret_cast<Game::source_t*>(1); Game::sourceFiles[i] = reinterpret_cast<Game::source_s*>(1);
return i; return i;
} }
Game::script_t* Menus::LoadMenuScript(const std::string& name, const std::string& buffer) Game::script_s* Menus::LoadMenuScript(const std::string& name, const std::string& buffer)
{ {
auto* script = static_cast<Game::script_t*>(Game::GetClearedMemory(sizeof(Game::script_t) + 1 + buffer.length())); auto* script = static_cast<Game::script_s*>(Game::GetClearedMemory(sizeof(Game::script_s) + 1 + buffer.length()));
if (!script) return nullptr; if (!script) return nullptr;
strcpy_s(script->filename, sizeof(script->filename), name.data()); strcpy_s(script->filename, sizeof(script->filename), name.data());
@ -136,7 +136,7 @@ namespace Components
return nullptr; return nullptr;
} }
Game::pc_token_t token; Game::pc_token_s token;
if (!Game::PC_ReadTokenHandle(handle, &token) || token.string[0] != '{') if (!Game::PC_ReadTokenHandle(handle, &token) || token.string[0] != '{')
{ {
allocator->free(menu->items); allocator->free(menu->items);
@ -195,8 +195,8 @@ namespace Components
if (!menuFile.exists()) return nullptr; if (!menuFile.exists()) return nullptr;
Game::pc_token_t token; Game::pc_token_s token;
int handle = LoadMenuSource(menu, menuFile.getBuffer()); const auto handle = LoadMenuSource(menu, menuFile.getBuffer());
if (IsValidSourceHandle(handle)) if (IsValidSourceHandle(handle))
{ {
@ -259,7 +259,7 @@ namespace Components
if (menuFile.exists()) if (menuFile.exists())
{ {
Game::pc_token_t token; Game::pc_token_s token;
const auto handle = LoadMenuSource(menu, menuFile.getBuffer()); const auto handle = LoadMenuSource(menu, menuFile.getBuffer());
if (IsValidSourceHandle(handle)) if (IsValidSourceHandle(handle))
@ -744,11 +744,11 @@ namespace Components
{ {
if (menu->window.name == "connect"s) // Check if we're supposed to draw the loadscreen if (menu->window.name == "connect"s) // Check if we're supposed to draw the loadscreen
{ {
Game::menuDef_t* originalConnect = AssetHandler::FindOriginalAsset(Game::XAssetType::ASSET_TYPE_MENU, "connect").menu; const auto* originalConnect = AssetHandler::FindOriginalAsset(Game::XAssetType::ASSET_TYPE_MENU, "connect").menu;
if (originalConnect == menu) // Check if we draw the original loadscreen if (originalConnect == menu) // Check if we draw the original loadscreen
{ {
if (MenuList.find("connect") != Menus::MenuList.end()) // Check if we have a custom loadscreen, to prevent drawing the original one on top if (MenuList.contains("connect")) // Check if we have a custom load screen, to prevent drawing the original one on top
{ {
return false; return false;
} }
@ -801,8 +801,8 @@ namespace Components
if (Dedicated::IsEnabled()) return; if (Dedicated::IsEnabled()) return;
// Intercept asset finding // Intercept asset finding
AssetHandler::OnFind(Game::XAssetType::ASSET_TYPE_MENU, MenuFindHook); AssetHandler::OnFind(Game::ASSET_TYPE_MENU, MenuFindHook);
AssetHandler::OnFind(Game::XAssetType::ASSET_TYPE_MENULIST, MenuListFindHook); AssetHandler::OnFind(Game::ASSET_TYPE_MENULIST, MenuListFindHook);
// Don't open connect menu // Don't open connect menu
// Utils::Hook::Nop(0x428E48, 5); // Utils::Hook::Nop(0x428E48, 5);

View File

@ -31,7 +31,7 @@ namespace Components
static void SafeMergeMenus(std::vector<std::pair<bool, Game::menuDef_t*>>* menus, std::vector<std::pair<bool, Game::menuDef_t*>> newMenus); static void SafeMergeMenus(std::vector<std::pair<bool, Game::menuDef_t*>>* menus, std::vector<std::pair<bool, Game::menuDef_t*>> newMenus);
static Game::script_t* LoadMenuScript(const std::string& name, const std::string& buffer); static Game::script_s* LoadMenuScript(const std::string& name, const std::string& buffer);
static int LoadMenuSource(const std::string& name, const std::string& buffer); static int LoadMenuSource(const std::string& name, const std::string& buffer);
static int ReserveSourceHandle(); static int ReserveSourceHandle();

View File

@ -669,7 +669,7 @@ namespace Components
} }
}); });
#ifdef DEBUG #ifdef DEBUG_MAT_LOG
AssetHandler::OnLoad([](Game::XAssetType type, Game::XAssetHeader asset, const std::string& /*name*/, bool* /*restrict*/) AssetHandler::OnLoad([](Game::XAssetType type, Game::XAssetHeader asset, const std::string& /*name*/, bool* /*restrict*/)
{ {
if (type == Game::XAssetType::ASSET_TYPE_GFXWORLD) if (type == Game::XAssetType::ASSET_TYPE_GFXWORLD)

View File

@ -130,11 +130,6 @@ namespace Game
Scr_AddSourceBuffer_t Scr_AddSourceBuffer = Scr_AddSourceBuffer_t(0x61ABC0); Scr_AddSourceBuffer_t Scr_AddSourceBuffer = Scr_AddSourceBuffer_t(0x61ABC0);
PC_FreeDefine_t PC_FreeDefine = PC_FreeDefine_t(0x4E0D60);
PC_ReadToken_t PC_ReadToken = PC_ReadToken_t(0x4ACCD0);
PC_ReadTokenHandle_t PC_ReadTokenHandle = PC_ReadTokenHandle_t(0x4D2060);
PC_SourceError_t PC_SourceError = PC_SourceError_t(0x467A00);
Party_GetMaxPlayers_t Party_GetMaxPlayers = Party_GetMaxPlayers_t(0x4F5D60); Party_GetMaxPlayers_t Party_GetMaxPlayers = Party_GetMaxPlayers_t(0x4F5D60);
PartyHost_CountMembers_t PartyHost_CountMembers = PartyHost_CountMembers_t(0x497330); PartyHost_CountMembers_t PartyHost_CountMembers = PartyHost_CountMembers_t(0x497330);
PartyHost_GetMemberAddressBySlot_t PartyHost_GetMemberAddressBySlot = PartyHost_GetMemberAddressBySlot_t(0x44E100); PartyHost_GetMemberAddressBySlot_t PartyHost_GetMemberAddressBySlot = PartyHost_GetMemberAddressBySlot_t(0x44E100);
@ -267,7 +262,7 @@ namespace Game
cmd_function_s** cmd_functions = reinterpret_cast<cmd_function_s**>(0x1AAC658); cmd_function_s** cmd_functions = reinterpret_cast<cmd_function_s**>(0x1AAC658);
source_t** sourceFiles = reinterpret_cast<source_t**>(0x7C4A98); source_s** sourceFiles = reinterpret_cast<source_s**>(0x7C4A98);
float* cgameFOVSensitivityScale = reinterpret_cast<float*>(0xB2F884); float* cgameFOVSensitivityScale = reinterpret_cast<float*>(0xB2F884);

View File

@ -320,18 +320,6 @@ namespace Game
typedef char*(*Scr_AddSourceBuffer_t)(const char* filename, const char* extFilename, const char* codePos, bool archive); typedef char*(*Scr_AddSourceBuffer_t)(const char* filename, const char* extFilename, const char* codePos, bool archive);
extern Scr_AddSourceBuffer_t Scr_AddSourceBuffer; extern Scr_AddSourceBuffer_t Scr_AddSourceBuffer;
typedef void(*PC_FreeDefine_t)(define_s* define);
extern PC_FreeDefine_t PC_FreeDefine;
typedef int(*PC_ReadToken_t)(source_t*, token_t*);
extern PC_ReadToken_t PC_ReadToken;
typedef int(*PC_ReadTokenHandle_t)(int handle, pc_token_s *pc_token);
extern PC_ReadTokenHandle_t PC_ReadTokenHandle;
typedef void(*PC_SourceError_t)(int, const char*, ...);
extern PC_SourceError_t PC_SourceError;
typedef int(*Party_GetMaxPlayers_t)(PartyData* party); typedef int(*Party_GetMaxPlayers_t)(PartyData* party);
extern Party_GetMaxPlayers_t Party_GetMaxPlayers; extern Party_GetMaxPlayers_t Party_GetMaxPlayers;
@ -611,7 +599,7 @@ namespace Game
extern float* cgameFOVSensitivityScale; extern float* cgameFOVSensitivityScale;
extern source_t** sourceFiles; extern source_s** sourceFiles;
extern UiContext* uiContext; extern UiContext* uiContext;

View File

@ -7,6 +7,7 @@
#include "FileSystem.hpp" #include "FileSystem.hpp"
#include "Functions.hpp" #include "Functions.hpp"
#include "Dvars.hpp" #include "Dvars.hpp"
#include "PreProcessor.hpp"
#include "Script.hpp" #include "Script.hpp"
#include "Server.hpp" #include "Server.hpp"
#include "System.hpp" #include "System.hpp"

86
src/Game/PreProcessor.cpp Normal file
View File

@ -0,0 +1,86 @@
#include <STDInclude.hpp>
namespace Game
{
PC_FreeDefine_t PC_FreeDefine = PC_FreeDefine_t(0x4E0D60);
PC_FindHashedDefine_t PC_FindHashedDefine = PC_FindHashedDefine_t(0x421E00);
PC_ReadToken_t PC_ReadToken = PC_ReadToken_t(0x4ACCD0);
PC_ReadTokenHandle_t PC_ReadTokenHandle = PC_ReadTokenHandle_t(0x4D2060);
PC_ReadSourceToken_t PC_ReadSourceToken = PC_ReadSourceToken_t(0x4B16F0);
PC_UnreadSourceToken_t PC_UnreadSourceToken = PC_UnreadSourceToken_t(0x47CD00);
PC_SourceError_t PC_SourceError = PC_SourceError_t(0x467A00);
SourceError_t SourceError = SourceError_t(0x44C6C0);
PC_Directive_if_def_t PC_Directive_if_def = PC_Directive_if_def_t(0x490A70);
PC_Directive_if_t PC_Directive_if = PC_Directive_if_t(0x486220);
PC_Directive_ifdef_t PC_Directive_ifdef = PC_Directive_ifdef_t(0x4F4ED0);
PC_Directive_ifndef_t PC_Directive_ifndef = PC_Directive_ifndef_t(0x42EF10);
PC_Directive_elif_t PC_Directive_elif = PC_Directive_elif_t(0x41AAB0);
PC_Directive_else_t PC_Directive_else = PC_Directive_else_t(0x4B55B0);
PC_Directive_endif_t PC_Directive_endif = PC_Directive_endif_t(0x491920);
PC_Directive_include_t PC_Directive_include = PC_Directive_include_t(0x495310);
PC_Directive_define_t PC_Directive_define = PC_Directive_define_t(0x42E460);
PC_Directive_undef_t PC_Directive_undef = PC_Directive_undef_t(0x4E1820);
PC_Directive_line_t PC_Directive_line = PC_Directive_line_t(0x4FD8A0);
PC_Directive_error_t PC_Directive_error = PC_Directive_error_t(0x494AA0);
PC_Directive_pragma_t PC_Directive_pragma = PC_Directive_pragma_t(0x42C160);
PC_Directive_eval_t PC_Directive_eval = PC_Directive_eval_t(0x57DB20);
PC_Directive_evalfloat_t PC_Directive_evalfloat = PC_Directive_evalfloat_t(0x4BC2A0);
__declspec(naked) int PC_ReadLine([[maybe_unused]] source_s* source, [[maybe_unused]] token_s* token, [[maybe_unused]] bool expandDefines)
{
static const DWORD PC_ReadLine_t = 0x57D830;
__asm
{
push eax
pushad
mov ebx, [esp + 0x24 + 0x4] // source
push [esp + 0x24 + 0xC] // expandDefines
push [esp + 0x24 + 0xC] // token
call PC_ReadLine_t
add esp, 0x8
mov [esp + 0x20], eax
popad
pop eax
ret
}
}
void PC_PushIndent(source_s* source, int type_, int skip)
{
static const DWORD PC_PushIndent_t = 0x57D740;
__asm
{
pushad
mov edi, skip
mov esi, source
push type_
call PC_PushIndent_t
add esp, 0x4
popad
}
}
void PC_PopIndent(source_s* source, int* type_, int* skip)
{
static const DWORD PC_PopIndent_t = 0x57D780;
__asm
{
pushad
mov edx, skip
mov eax, type_
mov ecx, source
call PC_PopIndent_t
popad
}
}
}

77
src/Game/PreProcessor.hpp Normal file
View File

@ -0,0 +1,77 @@
#pragma once
namespace Game
{
typedef void(*PC_FreeDefine_t)(define_s* define);
extern PC_FreeDefine_t PC_FreeDefine;
typedef define_s*(*PC_FindHashedDefine_t)(define_s** definehash, const char* name);
extern PC_FindHashedDefine_t PC_FindHashedDefine;
typedef int(*PC_ReadToken_t)(source_s*, token_s*);
extern PC_ReadToken_t PC_ReadToken;
typedef int(*PC_ReadTokenHandle_t)(int handle, pc_token_s* pc_token);
extern PC_ReadTokenHandle_t PC_ReadTokenHandle;
typedef int(*PC_ReadSourceToken_t)(source_s* source, token_s* token);
extern PC_ReadSourceToken_t PC_ReadSourceToken;
typedef int(*PC_UnreadSourceToken_t)(source_s* source, token_s* token);
extern PC_UnreadSourceToken_t PC_UnreadSourceToken;
typedef void(*PC_SourceError_t)(int, const char*, ...);
extern PC_SourceError_t PC_SourceError;
typedef void(*SourceError_t)(source_s* source, const char* str, ...);
extern SourceError_t SourceError;
typedef int(*PC_Directive_if_def_t)(source_s* source, int type);
extern PC_Directive_if_def_t PC_Directive_if_def;
typedef int(*PC_Directive_if_t)(source_s* source);
extern PC_Directive_if_t PC_Directive_if;
typedef int(*PC_Directive_ifdef_t)(source_s* source);
extern PC_Directive_ifdef_t PC_Directive_ifdef;
typedef int(*PC_Directive_ifndef_t)(source_s* source);
extern PC_Directive_ifndef_t PC_Directive_ifndef;
typedef int(*PC_Directive_elif_t)(source_s* source);
extern PC_Directive_elif_t PC_Directive_elif;
typedef int(*PC_Directive_else_t)(source_s* source);
extern PC_Directive_else_t PC_Directive_else;
typedef int(*PC_Directive_endif_t)(source_s* source);
extern PC_Directive_endif_t PC_Directive_endif;
typedef int(*PC_Directive_include_t)(source_s* source);
extern PC_Directive_include_t PC_Directive_include;
typedef int(*PC_Directive_define_t)(source_s* source);
extern PC_Directive_define_t PC_Directive_define;
typedef int(*PC_Directive_undef_t)(source_s* source);
extern PC_Directive_undef_t PC_Directive_undef;
typedef int(*PC_Directive_line_t)(source_s* source);
extern PC_Directive_line_t PC_Directive_line;
typedef int(*PC_Directive_error_t)(source_s* source);
extern PC_Directive_error_t PC_Directive_error;
typedef int(*PC_Directive_pragma_t)(source_s* source);
extern PC_Directive_pragma_t PC_Directive_pragma;
typedef int(*PC_Directive_eval_t)(source_s* source);
extern PC_Directive_eval_t PC_Directive_eval;
typedef int(*PC_Directive_evalfloat_t)(source_s* source);
extern PC_Directive_evalfloat_t PC_Directive_evalfloat;
extern int PC_ReadLine(source_s* source, token_s* token, bool expandDefines);
extern void PC_PushIndent(source_s* source, int type, int skip);
extern void PC_PopIndent(source_s* source, int* type, int* skip);
}

View File

@ -7367,31 +7367,38 @@ namespace Game
CModelSectionHeader sectionHeader[4]; CModelSectionHeader sectionHeader[4];
}; };
typedef struct punctuation_s struct punctuation_s
{ {
char* p; //punctuation character(s) char* p; //punctuation character(s)
int n; //punctuation indication int n; //punctuation indication
punctuation_s* next; //next punctuation punctuation_s* next; //next punctuation
} punctuation_t; };
#define MAX_TOKEN 1024 #define MAX_TOKEN 1024
#define MAX_TOKENLENGTH 1024 #define MAX_TOKENLENGTH 1024
typedef struct token_s enum parseSkip_t
{ {
char string[MAX_TOKEN]; //available token SKIP_NO = 0x0,
int type; //last read token type SKIP_YES = 0x1,
int subtype; //last read token sub type SKIP_ALL_ELIFS = 0x2,
unsigned long int intvalue; //integer value };
long double floatvalue; //floating point value
char* whitespace_p; //start of white space before token
char* endwhitespace_p; //start of white space before token
int line; //line the token was on
int linescrossed; //lines crossed in white space
token_s* next; //next token in chain
} token_t;
typedef struct script_s struct token_s
{
char string[MAX_TOKEN]; // available token
int type; // last read token type
int subtype; // last read token sub type
unsigned long int intvalue; // integer value
long double floatvalue; // floating point value
char* whitespace_p; // start of white space before token
char* endwhitespace_p; // start of white space before token
int line; // line the token was on
int linescrossed; // lines crossed in white space
token_s* next; // next token in chain
};
struct script_s
{ {
char filename[64]; //file name of the script char filename[64]; //file name of the script
char* buffer; //buffer containing the script char* buffer; //buffer containing the script
@ -7405,54 +7412,60 @@ namespace Game
int lastline; //line before reading token int lastline; //line before reading token
int tokenavailable; //set by UnreadLastToken int tokenavailable; //set by UnreadLastToken
int flags; //several script flags int flags; //several script flags
punctuation_t* punctuations; //the punctuations used in the script punctuation_s* punctuations; //the punctuations used in the script
punctuation_t** punctuationtable; punctuation_s** punctuationtable;
token_t token; //available token token_s token; //available token
script_s* next; //next script in a chain script_s* next; //next script in a chain
} script_t; };
typedef struct define_s struct define_s
{ {
char* name; //define name char* name; //define name
int flags; //define flags int flags; //define flags
int builtin; // > 0 if builtin define int builtin; // > 0 if builtin define
int numparms; //number of define parameters int numparms; //number of define parameters
token_t* parms; //define parameters token_s* parms; //define parameters
token_t* tokens; //macro tokens (possibly containing parm tokens) token_s* tokens; //macro tokens (possibly containing parm tokens)
define_s* next; //next defined macro in a list define_s* next; //next defined macro in a list
define_s* hashnext; //next define in the hash chain define_s* hashnext; //next define in the hash chain
} define_t; };
typedef struct indent_s struct indent_s
{ {
int type; //indent type int type; //indent type
int skip; //true if skipping current indent int skip; //true if skipping current indent
script_t* script; //script the indent was in script_s* script; //script the indent was in
indent_s* next; //next indent on the indent stack indent_s* next; //next indent on the indent stack
} indent_t; };
typedef struct source_s struct source_s
{ {
char filename[MAX_QPATH]; //file name of the script char filename[MAX_QPATH]; //file name of the script
char includepath[MAX_QPATH]; //path to include files char includepath[MAX_QPATH]; //path to include files
punctuation_t* punctuations; //punctuations to use punctuation_s* punctuations; //punctuations to use
script_t* scriptstack; //stack with scripts of the source script_s* scriptstack; //stack with scripts of the source
token_t* tokens; //tokens to read first token_s* tokens; //tokens to read first
define_t* defines; //list with macro definitions define_s* defines; //list with macro definitions
define_t** definehash; //hash chain with defines define_s** definehash; //hash chain with defines
indent_t* indentstack; //stack with indents indent_s* indentstack; //stack with indents
int skip; // > 0 if skipping conditional code int skip; // > 0 if skipping conditional code
token_t token; //last read token token_s token; //last read token
} source_t; };
typedef struct pc_token_s struct directive_s
{
const char* name;
int (*func)(source_s* source);
};
struct pc_token_s
{ {
int type; int type;
int subtype; int subtype;
int intvalue; int intvalue;
float floatvalue; float floatvalue;
char string[MAX_TOKENLENGTH]; char string[MAX_TOKENLENGTH];
} pc_token_t; };
template <typename T, int N, int M> template <typename T, int N, int M>
struct KeywordHashEntry struct KeywordHashEntry