2012-12-30 16:37:54 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// $Logfile:: /Code/DLLs/game/script.cpp $
|
|
|
|
// $Revision:: 18 $
|
|
|
|
// $Author:: Steven $
|
|
|
|
// $Date:: 10/13/03 9:11a $
|
|
|
|
//
|
|
|
|
// Copyright (C) 1997 by Ritual Entertainment, Inc.
|
|
|
|
// All rights reserved.
|
|
|
|
//
|
|
|
|
// This source is may not be distributed and/or modified without
|
|
|
|
// expressly written permission by Ritual Entertainment, Inc.
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// DESCRIPTION:
|
|
|
|
// 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 "_pch_cpp.h"
|
|
|
|
#include "script.h"
|
|
|
|
#include <qcommon/gameplaymanager.h>
|
|
|
|
|
|
|
|
#define TOKENCOMMENT (';')
|
|
|
|
#define TOKENCOMMENT2 ('#')
|
|
|
|
#define TOKENEOL ('\n')
|
|
|
|
//#define TOKENNULL ('\0')
|
|
|
|
#define TOKENSPACE (' ')
|
|
|
|
#define TOKENSPECIAL ('$')
|
|
|
|
|
|
|
|
CLASS_DECLARATION( Class, Script, NULL )
|
|
|
|
{
|
|
|
|
{ NULL, NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
Script::~Script()
|
|
|
|
{
|
|
|
|
Close();
|
|
|
|
}
|
|
|
|
|
|
|
|
Script::Script(const char* filename /*= 0*/)
|
|
|
|
{
|
|
|
|
buffer = NULL;
|
|
|
|
script_p = NULL;
|
|
|
|
end_p = NULL;
|
|
|
|
line = 0;
|
|
|
|
length = 0;
|
|
|
|
releaseBuffer = false;
|
|
|
|
tokenready = false;
|
|
|
|
memset( token, 0, sizeof( token ) );
|
|
|
|
|
|
|
|
if ( filename != 0 )
|
|
|
|
LoadFile(filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Script::Close( void )
|
|
|
|
{
|
|
|
|
if ( releaseBuffer && buffer )
|
|
|
|
{
|
|
|
|
gi.Free( ( void * )buffer );
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer = NULL;
|
|
|
|
script_p = NULL;
|
|
|
|
end_p = NULL;
|
|
|
|
line = 0;
|
|
|
|
releaseBuffer = false;
|
|
|
|
tokenready = false;
|
|
|
|
memset( token, 0, sizeof( token ) );
|
|
|
|
|
|
|
|
//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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= Filename
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
|
|
|
|
const char *Script::Filename( void )
|
|
|
|
{
|
|
|
|
return filename.c_str();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= GetLineNumber
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
|
|
|
|
int Script::GetLineNumber( void )
|
|
|
|
{
|
|
|
|
return line;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= Reset
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
|
|
|
|
void Script::Reset( void )
|
|
|
|
{
|
|
|
|
script_p = buffer;
|
|
|
|
line = 1;
|
|
|
|
tokenready = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= MarkPosition
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
|
|
|
|
void Script::MarkPosition( scriptmarker_t *mark )
|
|
|
|
{
|
|
|
|
assert( mark );
|
|
|
|
|
|
|
|
mark->tokenready = tokenready;
|
|
|
|
mark->offset = script_p - buffer;
|
|
|
|
mark->line = line;
|
|
|
|
strcpy( mark->token, token );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= RestorePosition
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
|
|
|
|
void Script::RestorePosition( const scriptmarker_t *mark )
|
|
|
|
{
|
|
|
|
assert( mark );
|
|
|
|
|
|
|
|
tokenready = mark->tokenready;
|
|
|
|
script_p = buffer + mark->offset;
|
|
|
|
line = mark->line;
|
|
|
|
strcpy( token, mark->token );
|
|
|
|
|
|
|
|
assert( script_p <= end_p );
|
|
|
|
if ( script_p > end_p )
|
|
|
|
{
|
|
|
|
script_p = end_p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= SkipToEOL
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
|
|
|
|
qboolean Script::SkipToEOL( void )
|
|
|
|
{
|
|
|
|
if ( script_p >= end_p )
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
while( *script_p != TOKENEOL )
|
|
|
|
{
|
|
|
|
if ( script_p >= end_p )
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
script_p++;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= CheckOverflow
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
|
|
|
|
void Script::CheckOverflow( void )
|
|
|
|
{
|
|
|
|
if ( script_p >= end_p )
|
|
|
|
{
|
|
|
|
gi.Error( ERR_DROP, "End of token file reached prematurely reading %s\n", filename.c_str() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= SkipWhiteSpace
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
|
|
|
|
void Script::SkipWhiteSpace( qboolean crossline )
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// skip space
|
|
|
|
//
|
|
|
|
CheckOverflow();
|
|
|
|
|
|
|
|
while( *script_p <= TOKENSPACE )
|
|
|
|
{
|
|
|
|
if ( *script_p++ == TOKENEOL )
|
|
|
|
{
|
|
|
|
if ( !crossline )
|
|
|
|
{
|
|
|
|
gi.Error( ERR_DROP, "Line %i is incomplete in file %s\n", line, filename.c_str() );
|
|
|
|
}
|
|
|
|
|
|
|
|
line++;
|
|
|
|
}
|
|
|
|
CheckOverflow();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
qboolean Script::AtComment( void )
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= SkipNonToken
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
|
|
|
|
void Script::SkipNonToken( qboolean crossline )
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// skip space and comments
|
|
|
|
//
|
|
|
|
SkipWhiteSpace( crossline );
|
|
|
|
while( AtComment() )
|
|
|
|
{
|
|
|
|
SkipToEOL();
|
|
|
|
SkipWhiteSpace( crossline );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=============================================================================
|
|
|
|
=
|
|
|
|
= Token section
|
|
|
|
=
|
|
|
|
=============================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= TokenAvailable
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
|
|
|
|
qboolean Script::TokenAvailable( qboolean crossline )
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= CommentAvailable
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
|
|
|
|
qboolean Script::CommentAvailable( qboolean crossline )
|
|
|
|
{
|
|
|
|
const char *searchptr;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= 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.
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
|
|
|
|
void Script::UnGetToken( void )
|
|
|
|
{
|
|
|
|
tokenready = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= Get
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
qboolean Script::AtString( qboolean crossline )
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// skip space
|
|
|
|
//
|
|
|
|
SkipNonToken( crossline );
|
|
|
|
|
|
|
|
return ( *script_p == '"' );
|
|
|
|
}
|
|
|
|
|
|
|
|
qboolean Script::AtOpenParen( qboolean crossline )
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// skip space
|
|
|
|
//
|
|
|
|
SkipNonToken( crossline );
|
|
|
|
|
|
|
|
return ( *script_p == '(' );
|
|
|
|
}
|
|
|
|
|
|
|
|
qboolean Script::AtCloseParen( qboolean crossline )
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// skip space
|
|
|
|
//
|
|
|
|
SkipNonToken( crossline );
|
|
|
|
|
|
|
|
return ( *script_p == ')' );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= Get
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
|
|
|
|
const char *Script::GetToken( qboolean crossline )
|
|
|
|
{
|
|
|
|
|
|
|
|
str token_p = token;
|
|
|
|
qboolean is_Macro = false;
|
|
|
|
|
|
|
|
// is a token already waiting?
|
|
|
|
if ( tokenready )
|
|
|
|
{
|
|
|
|
tokenready = false;
|
|
|
|
return token;
|
|
|
|
}
|
|
|
|
|
|
|
|
is_Macro = isMacro();
|
|
|
|
|
|
|
|
token_p = GrabNextToken(crossline);
|
|
|
|
|
|
|
|
if ( is_Macro && ( token_p != "$include" ) )
|
|
|
|
{
|
|
|
|
|
|
|
|
//Check to see if we need to add any definitions
|
|
|
|
while ( ( token_p == "$define" ) || ( token_p == "$Define" ) )
|
|
|
|
{
|
|
|
|
AddMacroDefinition(crossline);
|
|
|
|
is_Macro = isMacro();
|
|
|
|
//if ( !is_Macro )
|
|
|
|
// return "";
|
|
|
|
token_p = GrabNextToken(crossline);
|
|
|
|
}
|
|
|
|
|
|
|
|
//Check to see if we need return any defines strings
|
|
|
|
if( is_Macro && ( token_p != "$include" ) && ( token_p[token_p.length() - 1] == '$' ) )
|
|
|
|
{
|
|
|
|
return GetMacroString(token_p);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return token;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= GrabNextToken
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
const char *Script::GrabNextToken( qboolean crossline )
|
|
|
|
{
|
|
|
|
char *token_p;
|
|
|
|
|
|
|
|
//
|
|
|
|
// 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[ MAXTOKEN ] )
|
|
|
|
{
|
|
|
|
gi.Error( ERR_DROP, "Token too large on line %i in file %s\n", line, filename.c_str() );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( script_p == end_p )
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
*token_p = 0;
|
|
|
|
|
|
|
|
return token;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= AddMacroDefinition
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void Script::AddMacroDefinition( qboolean crossline )
|
|
|
|
{
|
|
|
|
macro *theMacro;
|
|
|
|
|
|
|
|
//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));
|
|
|
|
theMacro->macroName.append('$'); //<-- Adding closing ($) to keep formatting consistant
|
|
|
|
|
|
|
|
//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 );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= GetMacroString
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
const char *Script::GetMacroString( const char *theMacroName )
|
|
|
|
{
|
|
|
|
|
|
|
|
macro *theMacro =0; //Initialize this puppy
|
|
|
|
|
|
|
|
for( int i = 1; i <= macrolist.NumObjects(); i++)
|
|
|
|
{
|
|
|
|
theMacro = macrolist.ObjectAt( i );
|
|
|
|
|
|
|
|
if(!theMacro->macroName.cmp(theMacro->macroName.c_str(), theMacroName))
|
|
|
|
{
|
|
|
|
const char *text = theMacro->macroText.c_str();
|
|
|
|
|
|
|
|
// 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++;
|
|
|
|
|
|
|
|
GameplayManager *gpm = GameplayManager::getTheGameplayManager();
|
|
|
|
if ( gpm->isDefined(sptr) )
|
|
|
|
return gpm->getDefine(sptr).c_str();
|
|
|
|
|
|
|
|
// We didn't find what we were looking for
|
|
|
|
gi.Error( ERR_DROP, "No Macro Text found for %s in file %s\n", theMacroName, filename.c_str() );
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//================================================================
|
|
|
|
// 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
|
|
|
|
//
|
|
|
|
//================================================================
|
|
|
|
void Script::AddMacro(const char *name, const char *value)
|
|
|
|
{
|
2012-12-31 16:38:54 +00:00
|
|
|
Q_UNUSED(name);
|
|
|
|
Q_UNUSED(value);
|
2012-12-30 16:37:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= EvaluateMacroString
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
char *Script::EvaluateMacroString( const char *theMacroString )
|
|
|
|
{
|
|
|
|
static char evalText[255];
|
|
|
|
char buffer[255], *bufferptr = buffer, oper = '+', newoper = '+';
|
|
|
|
bool haveoper = false;
|
|
|
|
float value = 0.0f, val = 0.0f;
|
|
|
|
memset(buffer, 0, 255);
|
|
|
|
|
2012-12-31 12:37:16 +00:00
|
|
|
for ( unsigned i=0;i<=strlen(theMacroString);i++ )
|
2012-12-30 16:37:54 +00:00
|
|
|
{
|
|
|
|
if ( theMacroString[i] == '+' ) { haveoper = true; newoper = '+'; }
|
|
|
|
if ( theMacroString[i] == '-' ) { haveoper = true; newoper = '-'; }
|
|
|
|
if ( theMacroString[i] == '*' ) { haveoper = true; newoper = '*'; }
|
|
|
|
if ( theMacroString[i] == '/' ) { haveoper = true; newoper = '/'; }
|
|
|
|
if ( theMacroString[i] == 0 ) haveoper = true;
|
|
|
|
|
|
|
|
if ( haveoper )
|
|
|
|
{
|
|
|
|
if ( buffer[0] == '$' )
|
|
|
|
val = atof(GetMacroString(buffer));
|
|
|
|
else
|
|
|
|
val = atof(buffer);
|
|
|
|
|
|
|
|
value = EvaluateMacroMath(value, val, oper);
|
|
|
|
oper = newoper;
|
|
|
|
|
|
|
|
// Reset everything
|
|
|
|
haveoper = false;
|
|
|
|
memset(buffer, 0, 255);
|
|
|
|
bufferptr = buffer;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
*bufferptr = theMacroString[i];
|
|
|
|
bufferptr++;
|
|
|
|
}
|
|
|
|
|
|
|
|
sprintf(evalText,"%f",value);
|
|
|
|
return evalText;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= EvaluateMacroMath
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
float Script::EvaluateMacroMath(float value, float newval, char oper)
|
|
|
|
{
|
|
|
|
switch ( oper )
|
|
|
|
{
|
|
|
|
case '+' : value += newval; break;
|
|
|
|
case '-' : value -= newval; break;
|
|
|
|
case '*' : value *= newval; break;
|
|
|
|
case '/' : value /= newval; break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= isMacro
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
qboolean Script::isMacro( void )
|
|
|
|
{
|
|
|
|
if ( !TokenAvailable( true ) )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
SkipNonToken( true );
|
|
|
|
if ( *script_p == TOKENSPECIAL )
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= GetLine
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
|
|
|
|
const char *Script::GetLine( qboolean crossline )
|
|
|
|
{
|
|
|
|
const char *start;
|
|
|
|
int size;
|
|
|
|
|
|
|
|
// 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 < ( MAXTOKEN - 1 ) )
|
|
|
|
{
|
|
|
|
memcpy( token, start, size );
|
|
|
|
token[ size ] = '\0';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gi.Error( ERR_DROP, "Token too large on line %i in file %s\n", line, filename.c_str() );
|
|
|
|
}
|
|
|
|
|
|
|
|
return token;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= GetRaw
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
|
|
|
|
const char *Script::GetRaw( void )
|
|
|
|
{
|
|
|
|
const char *start;
|
|
|
|
int size;
|
|
|
|
|
|
|
|
//
|
|
|
|
// skip white space
|
|
|
|
//
|
|
|
|
SkipWhiteSpace( true );
|
|
|
|
|
|
|
|
//
|
|
|
|
// copy token
|
|
|
|
//
|
|
|
|
start = script_p;
|
|
|
|
SkipToEOL();
|
|
|
|
size = script_p - start;
|
|
|
|
if ( size < ( MAXTOKEN - 1 ) )
|
|
|
|
{
|
|
|
|
memset( token, 0, sizeof( token ) );
|
|
|
|
memcpy( token, start, size );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gi.Error( ERR_DROP, "Token too large on line %i in file %s\n", line, filename.c_str() );
|
|
|
|
}
|
|
|
|
|
|
|
|
return token;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= GetString
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
|
|
|
|
const char *Script::GetString( qboolean crossline )
|
|
|
|
{
|
|
|
|
int startline;
|
|
|
|
char *token_p;
|
|
|
|
|
|
|
|
// is a token already waiting?
|
|
|
|
if ( tokenready )
|
|
|
|
{
|
|
|
|
tokenready = false;
|
|
|
|
return token;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// skip space
|
|
|
|
//
|
|
|
|
SkipNonToken( crossline );
|
|
|
|
|
|
|
|
if ( *script_p != '"' )
|
|
|
|
{
|
|
|
|
gi.Error( ERR_DROP, "Expecting string on line %i in file %s\n", line, filename.c_str() );
|
|
|
|
}
|
|
|
|
|
|
|
|
script_p++;
|
|
|
|
|
|
|
|
startline = line;
|
|
|
|
token_p = token;
|
|
|
|
while( *script_p != '"' )
|
|
|
|
{
|
|
|
|
if ( *script_p == TOKENEOL )
|
|
|
|
{
|
|
|
|
gi.Error( ERR_DROP, "Line %i is incomplete while reading string in file %s\n", line, filename.c_str() );
|
|
|
|
}
|
|
|
|
|
|
|
|
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 )
|
|
|
|
{
|
|
|
|
gi.Error( ERR_DROP, "End of token file reached prematurely while reading string on\n"
|
|
|
|
"line %d in file %s\n", startline, filename.c_str() );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( token_p == &token[ MAXTOKEN ] )
|
|
|
|
{
|
|
|
|
gi.Error( ERR_DROP, "String too large on line %i in file %s\n", line, filename.c_str() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*token_p = 0;
|
|
|
|
|
|
|
|
// skip last quote
|
|
|
|
script_p++;
|
|
|
|
|
|
|
|
return token;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= GetSpecific
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
|
|
|
|
qboolean Script::GetSpecific( const char *string )
|
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if ( !TokenAvailable( true ) )
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
GetToken( true );
|
|
|
|
}
|
|
|
|
while( strcmp( token, string ) );
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===============================================================
|
|
|
|
// 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.
|
|
|
|
//
|
|
|
|
// Parameters: qboolean -- determines if token parsing can cross newlines
|
|
|
|
//
|
|
|
|
// Returns: qboolean -- true if next token was "true" (or "1")
|
|
|
|
//
|
|
|
|
//===============================================================
|
|
|
|
qboolean Script::GetBoolean( qboolean crossline )
|
|
|
|
{
|
|
|
|
GetToken( crossline );
|
|
|
|
if ( stricmp( token, "true" ) == 0 )
|
|
|
|
return qtrue ;
|
|
|
|
else if ( stricmp( token, "1" ) == 0 )
|
|
|
|
return qtrue ;
|
|
|
|
return qfalse ;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= GetInteger
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
|
|
|
|
int Script::GetInteger( qboolean crossline )
|
|
|
|
{
|
|
|
|
GetToken( crossline );
|
|
|
|
return atoi( token );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= GetDouble
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
|
|
|
|
double Script::GetDouble( qboolean crossline )
|
|
|
|
{
|
|
|
|
GetToken( crossline );
|
|
|
|
return atof( token );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= GetFloat
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
|
|
|
|
float Script::GetFloat( qboolean crossline )
|
|
|
|
{
|
|
|
|
return ( float )GetDouble( crossline );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= GetVector
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
|
|
|
|
Vector Script::GetVector( qboolean crossline )
|
|
|
|
{
|
|
|
|
float x = GetFloat( crossline );
|
|
|
|
float y = GetFloat( crossline );
|
|
|
|
float z = GetFloat( crossline );
|
|
|
|
return Vector( x, y, z );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
===================
|
|
|
|
=
|
|
|
|
= LinesInFile
|
|
|
|
=
|
|
|
|
===================
|
|
|
|
*/
|
|
|
|
int Script::LinesInFile( void )
|
|
|
|
{
|
|
|
|
qboolean temp_tokenready;
|
|
|
|
const char *temp_script_p;
|
|
|
|
int temp_line;
|
|
|
|
char temp_token[ MAXTOKEN ];
|
|
|
|
int numentries;
|
|
|
|
|
|
|
|
temp_tokenready = tokenready;
|
|
|
|
temp_script_p = script_p;
|
|
|
|
temp_line = line;
|
|
|
|
strcpy( temp_token, token );
|
|
|
|
|
|
|
|
numentries = 0;
|
|
|
|
|
|
|
|
Reset();
|
|
|
|
while( TokenAvailable( true ) )
|
|
|
|
{
|
|
|
|
GetLine( true );
|
|
|
|
numentries++;
|
|
|
|
}
|
|
|
|
|
|
|
|
tokenready = temp_tokenready;
|
|
|
|
script_p = temp_script_p;
|
|
|
|
line = temp_line;
|
|
|
|
strcpy( token, temp_token );
|
|
|
|
|
|
|
|
return numentries;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= Parse
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
|
|
|
|
void Script::Parse( const char *data, int length, const char *name )
|
|
|
|
{
|
|
|
|
Close();
|
|
|
|
|
|
|
|
buffer = data;
|
|
|
|
Reset();
|
|
|
|
end_p = script_p + length;
|
|
|
|
this->length = length;
|
|
|
|
filename = name;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= Load
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
|
|
|
|
void Script::LoadFile( const char *name )
|
|
|
|
{
|
|
|
|
int length;
|
|
|
|
byte *buffer;
|
|
|
|
byte *tempbuf;
|
|
|
|
const char *const_buffer;
|
|
|
|
|
|
|
|
Close();
|
|
|
|
|
|
|
|
length = gi.FS_ReadFile( name, ( void ** )&tempbuf, true );
|
|
|
|
if ( length < 0 )
|
|
|
|
{
|
|
|
|
error( "LoadFile", "Couldn't load %s\n", name );
|
|
|
|
}
|
|
|
|
// create our own space
|
|
|
|
buffer = ( byte * )gi.Malloc( length );
|
|
|
|
// copy the file over to our space
|
|
|
|
memcpy( buffer, tempbuf, length );
|
|
|
|
// free the file
|
|
|
|
gi.FS_FreeFile( tempbuf );
|
|
|
|
|
|
|
|
const_buffer = ( char * )buffer;
|
|
|
|
|
|
|
|
Parse( const_buffer, length, name );
|
|
|
|
releaseBuffer = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *Script::Token( void )
|
|
|
|
{
|
|
|
|
return token;
|
|
|
|
}
|