#include "cmdlib.h" #include "filelib.h" #include "messages.h" #include "log.h" #include "scriplib.h" char g_token[MAXTOKEN]; char g_TXcommand; typedef struct { char filename[_MAX_PATH]; char* buffer; char* script_p; char* end_p; int line; } script_t; #define MAX_INCLUDES 8 static script_t s_scriptstack[MAX_INCLUDES]; script_t* s_script; int s_scriptline; bool s_endofscript; bool s_tokenready; // only true if UnGetToken was just called // AddScriptToStack // LoadScriptFile // ParseFromMemory // UnGetToken // EndOfScript // GetToken // TokenAvailable // ===================================================================================== // AddScriptToStack // ===================================================================================== static void AddScriptToStack(const char* const filename) { int size; s_script++; if (s_script == &s_scriptstack[MAX_INCLUDES]) Error("s_script file exceeded MAX_INCLUDES"); strcpy_s(s_script->filename, filename); size = LoadFile(s_script->filename, (char**)&s_script->buffer); Log("Entering %s\n", s_script->filename); s_script->line = 1; s_script->script_p = s_script->buffer; s_script->end_p = s_script->buffer + size; } // ===================================================================================== // LoadScriptFile // ===================================================================================== void LoadScriptFile(const char* const filename) { s_script = s_scriptstack; AddScriptToStack(filename); s_endofscript = false; s_tokenready = false; } // ===================================================================================== // ParseFromMemory // ===================================================================================== void ParseFromMemory(char* buffer, const int size) { s_script = s_scriptstack; s_script++; if (s_script == &s_scriptstack[MAX_INCLUDES]) Error("s_script file exceeded MAX_INCLUDES"); strcpy_s(s_script->filename, "memory buffer"); s_script->buffer = buffer; s_script->line = 1; s_script->script_p = s_script->buffer; s_script->end_p = s_script->buffer + size; s_endofscript = false; s_tokenready = false; } // ===================================================================================== // UnGetToken /* * Signals that the current g_token was not used, and should be reported * for the next GetToken. Note that * * GetToken (true); * UnGetToken (); * GetToken (false); * * could cross a line boundary. */ // ===================================================================================== void UnGetToken() { s_tokenready = true; } // ===================================================================================== // EndOfScript // ===================================================================================== bool EndOfScript(const bool crossline) { if (!crossline) Error("Line %i is incomplete (did you place a \" inside an entity string?) \n", s_scriptline); if (!strcmp(s_script->filename, "memory buffer")) { s_endofscript = true; return false; } free(s_script->buffer); if (s_script == s_scriptstack + 1) { s_endofscript = true; return false; } s_script--; s_scriptline = s_script->line; Log("returning to %s\n", s_script->filename); return GetToken(crossline); } // ===================================================================================== // GetToken // ===================================================================================== bool GetToken(const bool crossline) { char *token_p; if (s_tokenready) // is a g_token allready waiting? { s_tokenready = false; return true; } if (s_script->script_p >= s_script->end_p) return EndOfScript(crossline); // skip space skipspace: while (*s_script->script_p <= 32) { if (s_script->script_p >= s_script->end_p) return EndOfScript(crossline); if (*s_script->script_p++ == '\n') { if (!crossline) Error("Line %i is incomplete (did you place a \" inside an entity string?) \n", s_scriptline); s_scriptline = s_script->line++; } } if (s_script->script_p >= s_script->end_p) return EndOfScript(crossline); // comment fields if (*s_script->script_p == ';' || *s_script->script_p == '#' || // semicolon and # is comment field (*s_script->script_p == '/' && *((s_script->script_p) + 1) == '/')) // also make // a comment field { if (!crossline) Error("Line %i is incomplete (did you place a \" inside an entity string?) \n", s_scriptline); //ets+++ if (*s_script->script_p == '/') s_script->script_p++; if (s_script->script_p[1] == 'T' && s_script->script_p[2] == 'X') g_TXcommand = s_script->script_p[3]; // AR: "//TX#"-style comment //ets--- while (*s_script->script_p++ != '\n') { if (s_script->script_p >= s_script->end_p) return EndOfScript(crossline); } //ets+++ s_scriptline = s_script->line++; // AR: this line was missing //ets--- goto skipspace; } // copy g_token token_p = g_token; if (*s_script->script_p == '"') { // quoted token s_script->script_p++; while (*s_script->script_p != '"') { *token_p++ = *s_script->script_p++; if (s_script->script_p == s_script->end_p) break; if (token_p == &g_token[MAXTOKEN]) Error("Token too large on line %i\n", s_scriptline); } s_script->script_p++; } else { // regular token while (*s_script->script_p > 32 && *s_script->script_p != ';') { *token_p++ = *s_script->script_p++; if (s_script->script_p == s_script->end_p) break; if (token_p == &g_token[MAXTOKEN]) Error("Token too large on line %i\n", s_scriptline); } } *token_p = 0; if (!strcmp(g_token, "$include")) { GetToken(false); AddScriptToStack(g_token); return GetToken(crossline); } return true; } #if 0 // AJM: THIS IS REDUNDANT // ===================================================================================== // ParseWadToken // basically the same as gettoken, except it isnt limited by MAXTOKEN and is // specificaly designed to parse out the wadpaths from the wad keyvalue and dump // them into the wadpaths list // this was implemented as a hack workaround for Token Too Large errors caused by // having long wadpaths or lots of wads in the map editor. extern void PushWadPath(const char* const path, bool inuse); // ===================================================================================== void ParseWadToken(const bool crossline) { // code somewhat copied from GetToken() int i, j; char* token_p; char temp[_MAX_PATH]; if (s_script->script_p >= s_script->end_p) return; // skip space while (*s_script->script_p <= 32) { if (s_script->script_p >= s_script->end_p) return; if (*s_script->script_p++ == '\n') { if (!crossline) Error("Line %i is incomplete (did you place a \" inside an entity string?) \n", s_scriptline); s_scriptline = s_script->line++; } } // EXPECT A QUOTE if (*s_script->script_p++ != '"') Error("Line %i: Expected a wadpaths definition, got '%s'\n", s_scriptline, *--s_script->script_p); // load wadpaths manually bool endoftoken = false; for (i = 0; !endoftoken; i++) { // get the path for (j = 0; ; j++) { token_p = ++s_script->script_p; // assert max path length if (j > _MAX_PATH) Error("Line %i: Wadpath definition %i is too long (%s)\n", s_scriptline, temp); if (*token_p == '\n') Error("Line %i: Expected a wadpaths definition, got linebreak\n", s_scriptline); if (*token_p == '"') // end of wadpath definition { if (i == 0 && j == 0) // no wadpaths! { Warning("No wadpaths specified.\n"); return; } endoftoken = true; break; } if (*token_p == ';') // end of this wadpath break; temp[j] = *token_p; temp[j + 1] = 0; } // push it into the list PushWadPath(temp, true); temp[0] = 0; } for (; *s_script->script_p != '\n'; s_script->script_p++) { } } #endif // ===================================================================================== // TokenAvailable // returns true if there is another token on the line // ===================================================================================== bool TokenAvailable() { char *search_p; search_p = s_script->script_p; if (search_p >= s_script->end_p) return false; while (*search_p <= 32) { if (*search_p == '\n') return false; search_p++; if (search_p == s_script->end_p) return false; } if (*search_p == ';') return false; return true; }