sin-sdk/script.cpp

964 lines
14 KiB
C++
Raw Normal View History

1998-12-20 00:00:00 +00:00
//-----------------------------------------------------------------------------
//
// $Logfile:: /Quake 2 Engine/Sin/code/game/script.cpp $
// $Revision:: 13 $
// $Author:: Jimdose $
// $Date:: 10/07/98 11:58p $
//
// 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.
//
// $Log:: /Quake 2 Engine/Sin/code/game/script.cpp $
//
// 13 10/07/98 11:58p Jimdose
// changed script_t to offset in script markers
//
// 12 6/09/98 4:21p Jimdose
// Added close
// filename is now a str
//
// 11 5/24/98 5:25p Jimdose
// Changed char *'s to const char *'s
//
// 10 3/26/98 3:57p Jimdose
// Made gettoken and getstring handle escape sequences (\n, \", etc.)
//
// 9 3/23/98 1:31p Jimdose
// Revamped event and command system
//
// 8 3/02/98 8:49p Jimdose
// Changed the classid parameter of CLASS_DECLARATION to a quoted string so
// that you could have a NULL classid.
//
// 7 2/17/98 7:13p Jimdose
// Added MarkPosition and RestorePosition
// Added atString for determining if the next token is a quoted string
// Made GetToken call GetString if the next token is a quoted string
// Fixed bug where GetSpecific wasn't properly updating the current line number
//
// 6 2/03/98 10:54a Jimdose
// Updated to work with Quake 2 engine
//
// 4 11/24/97 4:30p Markd
// Added GetVector
//
// 3 10/27/97 3:29p Jimdose
// Removed dependency on quakedef.h
//
// 2 9/26/97 6:14p Jimdose
// Added standard Ritual headers
//
// 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 "g_local.h"
#include "script.h"
#define TOKENCOMMENT (';')
#define TOKENCOMMENT2 ('#')
#define TOKENEOL ('\n')
#define TOKENNULL ('\0')
#define TOKENSPACE (' ')
CLASS_DECLARATION( Class, Script, NULL );
ResponseDef Script::Responses[] =
{
{ NULL, NULL }
};
Script::~Script()
{
Close();
}
Script::Script()
{
buffer = NULL;
script_p = NULL;
end_p = NULL;
line = 0;
releaseBuffer = false;
tokenready = false;
memset( token, 0, sizeof( token ) );
}
void Script::Close
(
void
)
{
if ( releaseBuffer && buffer )
{
gi.TagFree( ( void * )buffer );
}
buffer = NULL;
script_p = NULL;
end_p = NULL;
line = 0;
releaseBuffer = false;
tokenready = false;
memset( token, 0, sizeof( token ) );
}
/*
==============
=
= 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
(
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( "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( "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==false )
{
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 == '"' );
}
/*
==============
=
= Get
=
==============
*/
const char *Script::GetToken
(
qboolean crossline
)
{
char *token_p;
// is a token already waiting?
if ( tokenready )
{
tokenready = false;
return token;
}
//
// 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( "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;
}
/*
==============
=
= 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( "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( "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( "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( "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( "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( "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;
}
/*
==============
=
= 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
)
{
return Vector( GetFloat( crossline ), GetFloat( crossline ), GetFloat( crossline ) );
}
/*
===================
=
= 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;
const char *buffer;
Close();
length = gi.LoadFile( name, ( void ** )&buffer, TAG_GAME );
if ( length < 0 )
{
error( "LoadFile", "Couldn't load %s\n", name );
}
Parse( buffer, length, name );
releaseBuffer = true;
}
const char *Script::Token
(
void
)
{
return token;
}