openmohaa/code/qcommon/script.cpp

1192 lines
22 KiB
C++
Raw Normal View History

2016-03-27 11:49:47 +02:00
/*
===========================================================================
Copyright (C) 2015 the OpenMoHAA team
This file is part of OpenMoHAA source code.
OpenMoHAA source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
OpenMoHAA source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// script.cpp :
// C++ implementaion of tokenizing text interpretation. Class accepts filename
// to load or pointer to preloaded text data. Standard tokenizing operations
// such as skip white-space, get string, get integer, get float, get token,
// and skip line are implemented.
//
// Note: all '//', '#', and ';' are treated as comments. Probably should
// make this behaviour toggleable.
//
#include "script.h"
2023-01-29 20:59:31 +01:00
#if defined(GAME_DLL)
2023-07-05 21:23:39 +02:00
# include "../fgame/g_local.h"
2023-01-29 20:59:31 +01:00
2023-07-05 21:23:39 +02:00
# define FILE_FS_FreeFile gi.FS_FreeFile
# define FILE_FS_ReadFile(a, b) gi.FS_ReadFile(a, b, true)
# define FILE_Malloc gi.Malloc
# define FILE_Free gi.Free
# define FILE_Error gi.Error
2023-01-29 20:59:31 +01:00
#elif defined(CGAME_DLL)
2023-07-05 21:23:39 +02:00
# define FILE_FS_FreeFile cgi.FS_FreeFile
# define FILE_FS_ReadFile(a, b) cgi.FS_ReadFile(a, b, qtrue)
# define FILE_Malloc cgi.Malloc
# define FILE_Free cgi.Free
# define FILE_Error cgi.Error
2023-01-29 20:59:31 +01:00
#else
2023-07-05 21:23:39 +02:00
# include "qcommon.h"
2023-01-29 20:59:31 +01:00
2023-07-05 21:23:39 +02:00
# define FILE_FS_FreeFile FS_FreeFile
# define FILE_FS_ReadFile(a, b) FS_ReadFile(a, b)
# define FILE_Malloc Z_Malloc
# define FILE_Free Z_Free
# define FILE_Error Com_Error
2023-01-29 20:59:31 +01:00
#endif
2016-03-27 11:49:47 +02:00
typedef unsigned char byte;
2023-07-05 21:23:39 +02:00
CLASS_DECLARATION(Class, Script, NULL) {
2023-02-04 19:56:06 +01:00
{NULL, NULL}
2016-03-27 11:49:47 +02:00
};
2023-07-05 21:23:39 +02:00
Script::~Script()
{
Close();
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
Script::Script(const char *filename /*= 0*/)
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
buffer = NULL;
script_p = NULL;
end_p = NULL;
line = 0;
length = 0;
2023-02-04 19:56:06 +01:00
releaseBuffer = false;
2023-07-05 21:23:39 +02:00
tokenready = false;
token[0] = 0;
2023-02-04 19:56:06 +01:00
if (filename != 0) {
LoadFile(filename);
}
2016-03-27 11:49:47 +02:00
}
Script::Script()
{
2023-07-05 21:23:39 +02:00
buffer = NULL;
script_p = NULL;
end_p = NULL;
line = 0;
length = 0;
2023-02-04 19:56:06 +01:00
releaseBuffer = false;
2023-07-05 21:23:39 +02:00
tokenready = false;
token[0] = 0;
2016-03-27 11:49:47 +02:00
}
2023-02-04 19:56:06 +01:00
void Script::Close(void)
2016-03-27 11:49:47 +02:00
{
2023-02-04 19:56:06 +01:00
if (releaseBuffer && buffer) {
2023-07-05 21:23:39 +02:00
FILE_Free((void *)buffer);
2023-02-04 19:56:06 +01:00
}
2023-07-05 21:23:39 +02:00
buffer = NULL;
script_p = NULL;
end_p = NULL;
line = 0;
2023-02-04 19:56:06 +01:00
releaseBuffer = false;
2023-07-05 21:23:39 +02:00
tokenready = false;
token[0] = 0;
2023-02-04 19:56:06 +01:00
// Loop Through the macro container and delete (del33t -hehe) them all
for (int i = 1; i <= macrolist.NumObjects(); i++) {
if (macrolist.ObjectAt(i)) {
delete macrolist.ObjectAt(i);
macrolist.ObjectAt(i) = 0;
}
}
2016-03-27 11:49:47 +02:00
}
/*
==============
=
= Filename
=
==============
*/
2023-07-05 21:23:39 +02:00
const char *Script::Filename(void)
{
return filename.c_str();
}
2016-03-27 11:49:47 +02:00
/*
==============
=
= GetLineNumber
=
==============
*/
2023-07-05 21:23:39 +02:00
int Script::GetLineNumber(void)
{
return line;
}
2016-03-27 11:49:47 +02:00
/*
==============
=
= Reset
=
==============
*/
2023-02-04 19:56:06 +01:00
void Script::Reset(void)
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
script_p = buffer;
line = 1;
2023-02-04 19:56:06 +01:00
tokenready = false;
2023-07-05 21:23:39 +02:00
hasError = false;
2016-03-27 11:49:47 +02:00
}
/*
==============
=
= MarkPosition
=
==============
*/
2023-07-05 21:23:39 +02:00
void Script::MarkPosition(scriptmarker_t *mark)
2016-03-27 11:49:47 +02:00
{
2023-02-04 19:56:06 +01:00
assert(mark);
mark->tokenready = tokenready;
2023-07-05 21:23:39 +02:00
mark->offset = script_p - buffer;
mark->line = line;
2023-02-04 19:56:06 +01:00
strcpy(mark->token, token);
2016-03-27 11:49:47 +02:00
}
/*
==============
=
= RestorePosition
=
==============
*/
2023-07-05 21:23:39 +02:00
void Script::RestorePosition(const scriptmarker_t *mark)
2016-03-27 11:49:47 +02:00
{
2023-02-04 19:56:06 +01:00
assert(mark);
tokenready = mark->tokenready;
2023-07-05 21:23:39 +02:00
script_p = buffer + mark->offset;
line = mark->line;
2023-02-04 19:56:06 +01:00
strcpy(token, mark->token);
assert(script_p <= end_p);
if (script_p > end_p) {
script_p = end_p;
}
2016-03-27 11:49:47 +02:00
}
/*
==============
=
= SkipToEOL
=
==============
*/
2023-02-04 19:56:06 +01:00
qboolean Script::SkipToEOL(void)
2016-03-27 11:49:47 +02:00
{
2023-02-04 19:56:06 +01:00
if (script_p >= end_p) {
return true;
}
while (*script_p != TOKENEOL) {
if (script_p >= end_p) {
return true;
}
script_p++;
}
return false;
2016-03-27 11:49:47 +02:00
}
/*
==============
=
= CheckOverflow
=
==============
*/
2023-02-04 19:56:06 +01:00
void Script::CheckOverflow(void)
2016-03-27 11:49:47 +02:00
{
2023-02-04 19:56:06 +01:00
if (script_p >= end_p) {
2023-07-05 21:23:39 +02:00
FILE_Error(ERR_DROP, "End of token file reached prematurely reading %s\n", filename.c_str());
2023-02-04 19:56:06 +01:00
}
2016-03-27 11:49:47 +02:00
}
/*
==============
=
= SkipWhiteSpace
=
==============
*/
2023-02-04 19:56:06 +01:00
void Script::SkipWhiteSpace(qboolean crossline)
2016-03-27 11:49:47 +02:00
{
2023-02-04 19:56:06 +01:00
//
// skip space
//
CheckOverflow();
while (*script_p <= TOKENSPACE) {
if (*script_p++ == TOKENEOL) {
if (!crossline) {
2023-07-05 21:23:39 +02:00
FILE_Error(ERR_DROP, "Line %i is incomplete in file %s\n", line, filename.c_str());
2023-02-04 19:56:06 +01:00
}
line++;
}
CheckOverflow();
}
2016-03-27 11:49:47 +02:00
}
2023-02-04 19:56:06 +01:00
qboolean Script::AtComment(void)
2016-03-27 11:49:47 +02:00
{
2023-02-04 19:56:06 +01:00
if (script_p >= end_p) {
return false;
}
if (*script_p == TOKENCOMMENT) {
return true;
}
if (*script_p == TOKENCOMMENT2) {
return true;
}
// Two or more character comment specifiers
if ((script_p + 1) >= end_p) {
return false;
}
if ((*script_p == '/') && (*(script_p + 1) == '/')) {
return true;
}
return false;
2016-03-27 11:49:47 +02:00
}
/*
==============
=
= SkipNonToken
=
==============
*/
2023-02-04 19:56:06 +01:00
void Script::SkipNonToken(qboolean crossline)
2016-03-27 11:49:47 +02:00
{
2023-02-04 19:56:06 +01:00
//
// skip space and comments
//
SkipWhiteSpace(crossline);
while (AtComment()) {
SkipToEOL();
SkipWhiteSpace(crossline);
}
2016-03-27 11:49:47 +02:00
}
/*
=============================================================================
=
= Token section
=
=============================================================================
*/
/*
==============
=
= TokenAvailable
=
==============
*/
2023-02-04 19:56:06 +01:00
qboolean Script::TokenAvailable(qboolean crossline)
2016-03-27 11:49:47 +02:00
{
2023-02-04 19:56:06 +01:00
if (script_p >= end_p) {
return false;
}
while (1) {
while (*script_p <= TOKENSPACE) {
if (*script_p == TOKENEOL) {
if (!crossline) {
return (false);
}
line++;
}
script_p++;
if (script_p >= end_p) {
return false;
}
}
if (AtComment()) {
qboolean done;
done = SkipToEOL();
if (done) {
return false;
}
} else {
break;
}
}
return true;
2016-03-27 11:49:47 +02:00
}
/*
==============
=
= CommentAvailable
=
==============
*/
2023-02-04 19:56:06 +01:00
qboolean Script::CommentAvailable(qboolean crossline)
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
const char *searchptr;
2023-02-04 19:56:06 +01:00
searchptr = script_p;
if (searchptr >= end_p) {
return false;
}
while (*searchptr <= TOKENSPACE) {
if ((*searchptr == TOKENEOL) && (!crossline)) {
return false;
}
searchptr++;
if (searchptr >= end_p) {
return false;
}
}
return true;
2016-03-27 11:49:47 +02:00
}
/*
==============
=
= UnGet
=
= Signals that the current token was not used, and should be reported
= for the next GetToken. Note that
GetToken (true);
UnGetToken ();
GetToken (false);
= could cross a line boundary.
=
==============
*/
2023-07-05 21:23:39 +02:00
void Script::UnGetToken(void)
{
tokenready = true;
}
2016-03-27 11:49:47 +02:00
/*
==============
=
= Get
=
==============
*/
2023-02-04 19:56:06 +01:00
qboolean Script::AtString(qboolean crossline)
2016-03-27 11:49:47 +02:00
{
2023-02-04 19:56:06 +01:00
//
// skip space
//
SkipNonToken(crossline);
return (*script_p == '"');
2016-03-27 11:49:47 +02:00
}
2023-02-04 19:56:06 +01:00
qboolean Script::AtOpenParen(qboolean crossline)
2016-03-27 11:49:47 +02:00
{
2023-02-04 19:56:06 +01:00
//
// skip space
//
SkipNonToken(crossline);
return (*script_p == '(');
2016-03-27 11:49:47 +02:00
}
2023-02-04 19:56:06 +01:00
qboolean Script::AtCloseParen(qboolean crossline)
2016-03-27 11:49:47 +02:00
{
2023-02-04 19:56:06 +01:00
//
// skip space
//
SkipNonToken(crossline);
return (*script_p == ')');
2016-03-27 11:49:47 +02:00
}
2023-02-04 19:56:06 +01:00
qboolean Script::AtComma(qboolean crossline)
2016-03-27 11:49:47 +02:00
{
2023-02-04 19:56:06 +01:00
//
// skip space
//
SkipNonToken(crossline);
2016-03-27 11:49:47 +02:00
2023-02-04 19:56:06 +01:00
return (*script_p == ',');
2016-03-27 11:49:47 +02:00
}
2023-02-04 19:56:06 +01:00
qboolean Script::AtDot(qboolean crossline)
2016-03-27 11:49:47 +02:00
{
2023-02-04 19:56:06 +01:00
//
// skip space
//
SkipNonToken(crossline);
2016-03-27 11:49:47 +02:00
2023-02-04 19:56:06 +01:00
return (*script_p == '.');
2016-03-27 11:49:47 +02:00
}
2023-02-04 19:56:06 +01:00
qboolean Script::AtAssignment(qboolean crossline)
2016-03-27 11:49:47 +02:00
{
2023-02-04 19:56:06 +01:00
//
// skip space
//
SkipNonToken(crossline);
2023-07-05 21:23:39 +02:00
return (*script_p == '=') || ((*script_p == '+') && (*(script_p + 1) == '='))
|| ((*script_p == '-') && (*(script_p + 1) == '=')) || ((*script_p == '*') && (*(script_p + 1) == '='))
|| ((*script_p == '/') && (*(script_p + 1) == '='));
2016-03-27 11:49:47 +02:00
}
/*
==============
=
= Get
=
==============
*/
2023-07-05 21:23:39 +02:00
const char *Script::GetToken(qboolean crossline)
2016-03-27 11:49:47 +02:00
{
2023-08-19 21:17:52 +02:00
const char* token_p = token;
qboolean is_Macro = false;
2023-02-04 19:56:06 +01:00
// is a token already waiting?
if (tokenready) {
tokenready = false;
return token;
}
is_Macro = isMacro();
token_p = GrabNextToken(crossline);
2023-08-19 21:17:52 +02:00
if (is_Macro && (strcmp(token_p, "$include") != 0)) {
2023-02-04 19:56:06 +01:00
// Check to see if we need to add any definitions
2023-08-19 21:17:52 +02:00
while ((!strcmp(token_p, "$define")) || (!strcmp(token_p, "$Define"))) {
2023-02-04 19:56:06 +01:00
AddMacroDefinition(crossline);
is_Macro = isMacro();
// if ( !is_Macro )
// return "";
token_p = GrabNextToken(crossline);
}
// Check to see if we need return any defines strings
2023-08-19 21:17:52 +02:00
if (is_Macro && (strcmp(token_p, "$include") != 0) && (token_p[strlen(token_p) - 1] == '$')) {
2023-02-04 19:56:06 +01:00
return GetMacroString(token_p);
}
}
return token;
2016-03-27 11:49:47 +02:00
}
/*
==============
=
= GrabNextToken
=
==============
*/
2023-07-05 21:23:39 +02:00
const char *Script::GrabNextToken(qboolean crossline)
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
char *token_p;
2023-02-04 19:56:06 +01:00
//
// skip space
//
SkipNonToken(crossline);
//
// copy token
//
if (*script_p == '"') {
return GetString(crossline);
}
token_p = token;
while ((*script_p > TOKENSPACE) && !AtComment()) {
if ((*script_p == '\\') && (script_p < (end_p - 1))) {
script_p++;
switch (*script_p) {
case 'n':
*token_p++ = '\n';
break;
case 'r':
*token_p++ = '\n';
break;
case '\'':
*token_p++ = '\'';
break;
case '\"':
*token_p++ = '\"';
break;
case '\\':
*token_p++ = '\\';
break;
default:
*token_p++ = *script_p;
break;
}
script_p++;
} else {
*token_p++ = *script_p++;
}
if (token_p == &token[SCRIPT_MAXTOKEN]) {
2023-07-05 21:23:39 +02:00
FILE_Error(ERR_DROP, "Token too large on line %i in file %s\n", line, filename.c_str());
2023-02-04 19:56:06 +01:00
}
if (script_p == end_p) {
break;
}
}
*token_p = 0;
return token;
2016-03-27 11:49:47 +02:00
}
/*
==============
=
= AddMacroDefinition
=
==============
*/
2023-02-04 19:56:06 +01:00
void Script::AddMacroDefinition(qboolean crossline)
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
macro *theMacro;
2023-02-04 19:56:06 +01:00
// Create a new macro structure. This new macro will be deleted in the
// script close()
theMacro = new macro;
// Grab the macro name
theMacro->macroName = "$";
theMacro->macroName.append(GrabNextToken(crossline));
2023-07-05 21:23:39 +02:00
theMacro->macroName.append("$"); //<-- Adding closing ($) to keep formatting consistant
2023-02-04 19:56:06 +01:00
// Grab the macro string
str tmpstr;
tmpstr = GrabNextToken(crossline);
// Check to see if we need return any defines strings
if ((tmpstr != "$include") && (tmpstr[tmpstr.length() - 1] == '$')) {
theMacro->macroText = GetMacroString(tmpstr);
} else {
theMacro->macroText = tmpstr;
}
macrolist.AddObject(theMacro);
2016-03-27 11:49:47 +02:00
}
/*
==============
=
= GetMacroString
=
==============
*/
2023-07-05 21:23:39 +02:00
const char *Script::GetMacroString(const char *theMacroName)
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
macro *theMacro = 0; // Initialize this puppy
2023-02-04 19:56:06 +01:00
for (int i = 1; i <= macrolist.NumObjects(); i++) {
theMacro = macrolist.ObjectAt(i);
2023-07-05 21:23:39 +02:00
if (!theMacro->macroName.cmp(theMacro->macroName.c_str(), theMacroName)) {
const char *text = theMacro->macroText.c_str();
2023-02-04 19:56:06 +01:00
// If our define value is another define...
if (text[0] == '$') {
return EvaluateMacroString(text);
} else {
return text;
}
}
}
char tmpstr[255], *sptr = tmpstr;
strcpy(tmpstr, theMacroName);
tmpstr[strlen(tmpstr) - 1] = 0;
sptr++;
// We didn't find what we were looking for
2023-07-05 21:23:39 +02:00
FILE_Error(ERR_DROP, "No Macro Text found for %s in file %s\n", theMacroName, filename.c_str());
2023-02-04 19:56:06 +01:00
return 0;
2016-03-27 11:49:47 +02:00
}
//================================================================
// Name: AddMacro
// Class: Script
//
// Description: Adds a macro to the definitions list.
//
// Parameters: const char *name -- Name of the macro
// const char *value -- Value
//
// Returns: None
//
//================================================================
2023-07-05 21:23:39 +02:00
void Script::AddMacro(const char *name, const char *value) {}
2016-03-27 11:49:47 +02:00
/*
==============
=
= EvaluateMacroString
=
==============
*/
2023-07-05 21:23:39 +02:00
char *Script::EvaluateMacroString(const char *theMacroString)
2016-03-27 11:49:47 +02:00
{
2023-02-04 19:56:06 +01:00
static char evalText[255];
2023-07-05 21:23:39 +02:00
char buffer[255], *bufferptr = buffer, oper = '+', newoper = '+';
bool haveoper = false;
int i;
float value = 0.0f, val = 0.0f;
2023-02-04 19:56:06 +01:00
memset(buffer, 0, 255);
for (i = 0; i <= strlen(theMacroString); i++) {
if (theMacroString[i] == '+') {
haveoper = true;
2023-07-05 21:23:39 +02:00
newoper = '+';
2023-02-04 19:56:06 +01:00
}
if (theMacroString[i] == '-') {
haveoper = true;
2023-07-05 21:23:39 +02:00
newoper = '-';
2023-02-04 19:56:06 +01:00
}
if (theMacroString[i] == '*') {
haveoper = true;
2023-07-05 21:23:39 +02:00
newoper = '*';
2023-02-04 19:56:06 +01:00
}
if (theMacroString[i] == '/') {
haveoper = true;
2023-07-05 21:23:39 +02:00
newoper = '/';
2023-02-04 19:56:06 +01:00
}
if (theMacroString[i] == 0) {
haveoper = true;
}
if (haveoper) {
if (buffer[0] == '$') {
val = atof(GetMacroString(buffer));
} else {
val = atof(buffer);
}
value = EvaluateMacroMath(value, val, oper);
2023-07-05 21:23:39 +02:00
oper = newoper;
2023-02-04 19:56:06 +01:00
// Reset everything
haveoper = false;
memset(buffer, 0, 255);
bufferptr = buffer;
continue;
}
*bufferptr = theMacroString[i];
bufferptr++;
}
sprintf(evalText, "%f", value);
return evalText;
2016-03-27 11:49:47 +02:00
}
/*
==============
=
= EvaluateMacroMath
=
==============
*/
float Script::EvaluateMacroMath(float value, float newval, char oper)
{
2023-02-04 19:56:06 +01:00
switch (oper) {
case '+':
value += newval;
break;
case '-':
value -= newval;
break;
case '*':
value *= newval;
break;
case '/':
value /= newval;
break;
}
return value;
2016-03-27 11:49:47 +02:00
}
/*
==============
=
= isMacro
=
==============
*/
2023-02-04 19:56:06 +01:00
qboolean Script::isMacro(void)
2016-03-27 11:49:47 +02:00
{
2023-02-04 19:56:06 +01:00
if (!TokenAvailable(true)) {
return false;
}
SkipNonToken(true);
if (*script_p == TOKENSPECIAL) {
return true;
}
return false;
2016-03-27 11:49:47 +02:00
}
/*
==============
=
= GetLine
=
==============
*/
2023-07-05 21:23:39 +02:00
const char *Script::GetLine(qboolean crossline)
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
const char *start;
int size;
2023-02-04 19:56:06 +01:00
// is a token already waiting?
if (tokenready) {
tokenready = false;
return token;
}
//
// skip space
//
SkipNonToken(crossline);
//
// copy token
//
start = script_p;
SkipToEOL();
size = script_p - start;
if (size < (SCRIPT_MAXTOKEN - 1)) {
2023-02-04 19:56:06 +01:00
memcpy(token, start, size);
token[size] = '\0';
} else {
2023-07-05 21:23:39 +02:00
FILE_Error(ERR_DROP, "Token too large on line %i in file %s\n", line, filename.c_str());
2023-02-04 19:56:06 +01:00
}
return token;
2016-03-27 11:49:47 +02:00
}
/*
==============
=
= GetRaw
=
==============
*/
2023-07-05 21:23:39 +02:00
const char *Script::GetRaw(void)
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
const char *start;
int size;
2023-02-04 19:56:06 +01:00
//
// skip white space
//
SkipWhiteSpace(true);
//
// copy token
//
start = script_p;
SkipToEOL();
size = script_p - start;
if (size < (SCRIPT_MAXTOKEN - 1)) {
2023-02-04 19:56:06 +01:00
memset(token, 0, sizeof(token));
memcpy(token, start, size);
} else {
2023-07-05 21:23:39 +02:00
FILE_Error(ERR_DROP, "Token too large on line %i in file %s\n", line, filename.c_str());
2023-02-04 19:56:06 +01:00
}
return token;
2016-03-27 11:49:47 +02:00
}
/*
==============
=
= GetString
=
==============
*/
2023-07-05 21:23:39 +02:00
const char *Script::GetString(qboolean crossline)
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
int startline;
char *token_p;
2023-02-04 19:56:06 +01:00
// is a token already waiting?
if (tokenready) {
tokenready = false;
return token;
}
//
// skip space
//
SkipNonToken(crossline);
if (*script_p != '"') {
2023-07-05 21:23:39 +02:00
FILE_Error(ERR_DROP, "Expecting string on line %i in file %s\n", line, filename.c_str());
2023-02-04 19:56:06 +01:00
}
script_p++;
startline = line;
2023-07-05 21:23:39 +02:00
token_p = token;
2023-02-04 19:56:06 +01:00
while (*script_p != '"') {
if (*script_p == TOKENEOL) {
2023-07-05 21:23:39 +02:00
FILE_Error(ERR_DROP, "Line %i is incomplete while reading string in file %s\n", line, filename.c_str());
2023-02-04 19:56:06 +01:00
}
if ((*script_p == '\\') && (script_p < (end_p - 1))) {
script_p++;
switch (*script_p) {
case 'n':
*token_p++ = '\n';
break;
case 'r':
*token_p++ = '\n';
break;
case '\'':
*token_p++ = '\'';
break;
case '\"':
*token_p++ = '\"';
break;
case '\\':
*token_p++ = '\\';
break;
default:
*token_p++ = *script_p;
break;
}
script_p++;
} else {
*token_p++ = *script_p++;
}
if (script_p >= end_p) {
2023-07-05 21:23:39 +02:00
FILE_Error(
ERR_DROP,
"End of token file reached prematurely while reading "
"string on\n"
"line %d in file %s\n",
startline,
filename.c_str()
);
2023-02-04 19:56:06 +01:00
}
if (token_p == &token[SCRIPT_MAXTOKEN]) {
2023-07-05 21:23:39 +02:00
FILE_Error(ERR_DROP, "String too large on line %i in file %s\n", line, filename.c_str());
2023-02-04 19:56:06 +01:00
}
}
*token_p = 0;
// skip last quote
script_p++;
return token;
2016-03-27 11:49:47 +02:00
}
/*
==============
=
= GetSpecific
=
==============
*/
2023-07-05 21:23:39 +02:00
qboolean Script::GetSpecific(const char *string)
2016-03-27 11:49:47 +02:00
{
2023-02-04 19:56:06 +01:00
do {
if (!TokenAvailable(true)) {
return false;
}
GetToken(true);
} while (strcmp(token, string));
return true;
2016-03-27 11:49:47 +02:00
}
//===============================================================
// Name: GetBoolean
// Class: Script
//
// Description: Retrieves the next boolean value in the token
// stream. If the next token is either "true"
// or "1", then it returns true. Otherwise, it
// returns false.
2023-02-04 19:56:06 +01:00
//
2016-03-27 11:49:47 +02:00
// Parameters: qboolean -- determines if token parsing can cross newlines
//
// Returns: qboolean -- true if next token was "true" (or "1")
2023-02-04 19:56:06 +01:00
//
2016-03-27 11:49:47 +02:00
//===============================================================
2023-02-04 19:56:06 +01:00
qboolean Script::GetBoolean(qboolean crossline)
2016-03-27 11:49:47 +02:00
{
2023-02-04 19:56:06 +01:00
GetToken(crossline);
if (Q_stricmp(token, "true") == 0) {
return true;
} else if (Q_stricmp(token, "1") == 0) {
return true;
}
return false;
2016-03-27 11:49:47 +02:00
}
/*
==============
=
= GetInteger
=
==============
*/
2023-02-04 19:56:06 +01:00
int Script::GetInteger(qboolean crossline)
2016-03-27 11:49:47 +02:00
{
2023-02-04 19:56:06 +01:00
GetToken(crossline);
return atoi(token);
2016-03-27 11:49:47 +02:00
}
/*
==============
=
= GetDouble
=
==============
*/
2023-02-04 19:56:06 +01:00
double Script::GetDouble(qboolean crossline)
2016-03-27 11:49:47 +02:00
{
2023-02-04 19:56:06 +01:00
GetToken(crossline);
return atof(token);
2016-03-27 11:49:47 +02:00
}
/*
==============
=
= GetFloat
=
==============
*/
2023-02-04 19:56:06 +01:00
float Script::GetFloat(qboolean crossline)
2016-03-27 11:49:47 +02:00
{
2023-02-04 19:56:06 +01:00
return (float)GetDouble(crossline);
2016-03-27 11:49:47 +02:00
}
/*
==============
=
= GetVector
=
==============
*/
2023-02-04 19:56:06 +01:00
Vector Script::GetVector(qboolean crossline)
2016-03-27 11:49:47 +02:00
{
2023-02-04 19:56:06 +01:00
float x = GetFloat(crossline);
float y = GetFloat(crossline);
float z = GetFloat(crossline);
return Vector(x, y, z);
2016-03-27 11:49:47 +02:00
}
/*
===================
=
= LinesInFile
=
===================
*/
2023-02-04 19:56:06 +01:00
int Script::LinesInFile(void)
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
qboolean temp_tokenready;
const char *temp_script_p;
int temp_line;
char temp_token[SCRIPT_MAXTOKEN];
int numentries;
2023-02-04 19:56:06 +01:00
temp_tokenready = tokenready;
2023-07-05 21:23:39 +02:00
temp_script_p = script_p;
temp_line = line;
2023-02-04 19:56:06 +01:00
strcpy(temp_token, token);
numentries = 0;
Reset();
while (TokenAvailable(true)) {
GetLine(true);
numentries++;
}
tokenready = temp_tokenready;
2023-07-05 21:23:39 +02:00
script_p = temp_script_p;
line = temp_line;
2023-02-04 19:56:06 +01:00
strcpy(token, temp_token);
return numentries;
2016-03-27 11:49:47 +02:00
}
/*
==============
=
= Parse
=
==============
*/
2023-07-05 21:23:39 +02:00
void Script::Parse(const char *data, size_t length, const char *name)
2016-03-27 11:49:47 +02:00
{
2023-02-04 19:56:06 +01:00
Close();
buffer = data;
Reset();
this->length = length;
2023-07-05 21:23:39 +02:00
end_p = script_p + length;
filename = name;
2016-03-27 11:49:47 +02:00
}
/*
==============
=
= Load
=
==============
*/
2023-07-05 21:23:39 +02:00
void Script::LoadFile(const char *name)
2016-03-27 11:49:47 +02:00
{
2023-07-05 21:23:39 +02:00
int length;
byte *buffer;
byte *tempbuf;
const char *const_buffer;
2023-02-04 19:56:06 +01:00
Close();
2023-07-05 21:23:39 +02:00
length = FILE_FS_ReadFile(name, (void **)&tempbuf);
2023-02-04 19:56:06 +01:00
hasError = false;
if (length < 0) {
hasError = true;
return;
}
// create our own space
2023-07-05 21:23:39 +02:00
buffer = (byte *)FILE_Malloc(length + 1);
2023-02-04 19:56:06 +01:00
// copy the file over to our space
memcpy(buffer, tempbuf, length);
buffer[length] = 0;
// free the file
FILE_FS_FreeFile(tempbuf);
2023-07-05 21:23:39 +02:00
const_buffer = (char *)buffer;
2023-02-04 19:56:06 +01:00
Parse(const_buffer, length, name);
releaseBuffer = true;
2016-03-27 11:49:47 +02:00
}
/*
==============
=
= LoadFile
=
==============
*/
2023-07-05 21:23:39 +02:00
void Script::LoadFile(const char *name, int length, const char *buf)
2016-03-27 11:49:47 +02:00
{
2023-02-04 19:56:06 +01:00
Close();
2016-03-27 11:49:47 +02:00
2023-02-04 19:56:06 +01:00
// create our own space
2023-07-05 21:23:39 +02:00
this->buffer = (const char *)FILE_Malloc(length);
2023-02-04 19:56:06 +01:00
this->length = length;
// copy the file over to our space
2023-07-05 21:23:39 +02:00
memcpy((void *)this->buffer, buf, length);
2016-03-27 11:49:47 +02:00
2023-02-04 19:56:06 +01:00
Parse(buffer, this->length, name);
releaseBuffer = true;
2016-03-27 11:49:47 +02:00
}
2023-07-05 21:23:39 +02:00
qboolean Script::isValid()
{
return !hasError;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
qboolean Script::EndOfFile(void)
{
return script_p >= end_p;
}
2016-03-27 11:49:47 +02:00
2023-07-05 21:23:39 +02:00
const char *Script::Token(void)
{
return token;
}