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
|
|
|
|
===========================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
// tiki_parse.cpp : TIKI Script
|
|
|
|
|
|
|
|
#include "q_shared.h"
|
|
|
|
#include "qcommon.h"
|
|
|
|
#include <tiki.h>
|
|
|
|
|
|
|
|
TikiScript *TikiScript::currentScript;
|
|
|
|
|
|
|
|
TikiScript::~TikiScript()
|
|
|
|
{
|
|
|
|
Close();
|
|
|
|
}
|
|
|
|
|
|
|
|
TikiScript::TikiScript()
|
|
|
|
{
|
|
|
|
error = false;
|
|
|
|
buffer = NULL;
|
|
|
|
script_p = NULL;
|
|
|
|
end_p = NULL;
|
|
|
|
line = 0;
|
|
|
|
releaseBuffer = false;
|
|
|
|
tokenready = false;
|
|
|
|
memset( token, 0, sizeof( token ) );
|
|
|
|
include = NULL;
|
|
|
|
parent = NULL;
|
|
|
|
nummacros = 0;
|
|
|
|
mark_pos = 0;
|
|
|
|
path[ 0 ] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= Close
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void TikiScript::Close( void )
|
|
|
|
{
|
|
|
|
Uninclude();
|
|
|
|
if( this->releaseBuffer )
|
|
|
|
{
|
|
|
|
if( this->buffer )
|
|
|
|
TIKI_Free( this->buffer );
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer = NULL;
|
|
|
|
script_p = NULL;
|
|
|
|
end_p = NULL;
|
|
|
|
line = 0;
|
|
|
|
error = false;
|
|
|
|
releaseBuffer = false;
|
|
|
|
tokenready = false;
|
|
|
|
nummacros = 0;
|
|
|
|
memset( token, 0, sizeof( token ) );
|
|
|
|
mark_pos = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= Filename
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
const char *TikiScript::Filename()
|
|
|
|
{
|
|
|
|
return filename;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= GetLineNumber
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
int TikiScript::GetLineNumber()
|
|
|
|
{
|
|
|
|
return line;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= Reset
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void TikiScript::Reset( void )
|
|
|
|
{
|
|
|
|
Uninclude();
|
|
|
|
|
|
|
|
nummacros = 0;
|
|
|
|
error = 0;
|
|
|
|
line = 1;
|
|
|
|
tokenready = 0;
|
|
|
|
mark_pos = 0;
|
|
|
|
script_p = buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= SkipToEOL
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
qboolean TikiScript::SkipToEOL( void )
|
|
|
|
{
|
|
|
|
if( script_p >= end_p )
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
while( *script_p != TOKENEOL )
|
|
|
|
{
|
|
|
|
if( script_p >= end_p )
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
script_p++;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= SafeCheckOverflow
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
qboolean TikiScript::SafeCheckOverflow( void )
|
|
|
|
{
|
|
|
|
return script_p >= end_p;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= CheckOverflow
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void TikiScript::CheckOverflow( void )
|
|
|
|
{
|
|
|
|
if( script_p >= end_p )
|
|
|
|
{
|
|
|
|
this->error = 1;
|
|
|
|
TIKI_DPrintf( "End of tiki file reached prematurely reading %s\n", Filename() );
|
|
|
|
TIKI_DPrintf( " This may be caused by having a tiki file command at the end of the file\n" );
|
|
|
|
TIKI_DPrintf( " without an 'end' at the end of the tiki file.\n" );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= SkipWhiteSpace
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void TikiScript::SkipWhiteSpace( qboolean crossline )
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// skip space
|
|
|
|
//
|
|
|
|
while( !SafeCheckOverflow() )
|
|
|
|
{
|
|
|
|
if( *script_p <= TOKENSPACE )
|
|
|
|
{
|
|
|
|
if( *script_p == TOKENEOL )
|
|
|
|
{
|
|
|
|
if( !crossline )
|
|
|
|
{
|
|
|
|
TIKI_DPrintf( "Line %i is incomplete in file %s\n", line, Filename() );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
line++;
|
|
|
|
}
|
|
|
|
script_p++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( !AtComment() )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( AtExtendedComment() )
|
|
|
|
{
|
|
|
|
SkipExtendedComment();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( !crossline )
|
|
|
|
{
|
|
|
|
TIKI_DPrintf( "Line %i is incomplete in file %s\n", line, Filename() );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
SkipToEOL();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= AtComment
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
qboolean TikiScript::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 ) == '/' ) || ( *( script_p + 1 ) == '*' ) ) )
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= AtExtendedComment
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
qboolean TikiScript::AtExtendedComment( void )
|
|
|
|
{
|
|
|
|
if( script_p >= end_p )
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Two or more character comment specifiers
|
|
|
|
if( ( script_p + 1 ) >= end_p )
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( ( *( script_p ) == '/' ) && ( *( script_p + 1 ) == '*' ) )
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= SkipExtendedComment
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void TikiScript::SkipExtendedComment( void )
|
|
|
|
{
|
|
|
|
CheckOverflow();
|
|
|
|
|
|
|
|
if( error )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while( ( script_p + 1 ) < end_p )
|
|
|
|
{
|
|
|
|
if( ( *( script_p ) == '*' ) && ( *( script_p + 1 ) == '/' ) )
|
|
|
|
{
|
|
|
|
script_p = script_p + 2;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( *script_p == '\n' )
|
|
|
|
line++;
|
|
|
|
|
|
|
|
script_p++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= AtCommand
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
qboolean TikiScript::AtCommand( void )
|
|
|
|
{
|
|
|
|
if( script_p >= end_p )
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Two or more character comment specifiers
|
|
|
|
if( ( script_p + 1 ) >= end_p )
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( ( *script_p == '$' ) && ( *( script_p + 1 ) != '$' ) )
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= Uninclude
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void TikiScript::Uninclude( void )
|
|
|
|
{
|
|
|
|
if( include )
|
|
|
|
{
|
|
|
|
currentScript = this;
|
|
|
|
include->Close();
|
|
|
|
delete include;
|
|
|
|
include = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= AddMacro
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void TikiScript::AddMacro( const char *name, const char *expansion )
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for( i = 0; i < nummacros; i++ )
|
|
|
|
{
|
|
|
|
if( !stricmp( name, macros[ i ].name ) )
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-05-21 00:29:26 +02:00
|
|
|
if( nummacros >= TIKI_MAXMACROS )
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
|
|
|
TIKI_DPrintf( "Too many %cdefine in file %s\n", TOKENSPECIAL, Filename() );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strcpy( macros[ nummacros ].name, name );
|
|
|
|
strcpy( macros[ nummacros ].macro, expansion );
|
|
|
|
nummacros++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add the macro to parent
|
|
|
|
if( parent )
|
|
|
|
parent->AddMacro( name, expansion );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= ProcessCommand
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
qboolean TikiScript::ProcessCommand( qboolean crossline )
|
|
|
|
{
|
2017-02-19 21:59:49 +01:00
|
|
|
char dummy;
|
2016-03-27 11:49:47 +02:00
|
|
|
int i;
|
|
|
|
size_t len;
|
|
|
|
char command[ 256 ];
|
|
|
|
char argument1[ 256 ];
|
|
|
|
char argument2[ 256 ];
|
|
|
|
|
2023-05-21 00:29:26 +02:00
|
|
|
sscanf( script_p, "%c%s %s %s\n", &dummy, command, argument1, argument2 );
|
2016-03-27 11:49:47 +02:00
|
|
|
|
|
|
|
if( !stricmp( command, "define" ) )
|
|
|
|
{
|
|
|
|
AddMacro( argument1, argument2 );
|
|
|
|
SkipToEOL();
|
|
|
|
SkipWhiteSpace( crossline );
|
|
|
|
}
|
|
|
|
else if( !stricmp( command, "include" ) )
|
|
|
|
{
|
|
|
|
SkipToEOL();
|
|
|
|
SkipWhiteSpace( crossline );
|
|
|
|
include = new TikiScript;
|
|
|
|
if( include->LoadFile( argument1, qfalse ) )
|
|
|
|
{
|
|
|
|
include->SkipNonToken( crossline );
|
|
|
|
for( i = 0; i < nummacros; i++ )
|
|
|
|
{
|
|
|
|
include->AddMacro( macros[ i ].name, macros[ i ].macro );
|
|
|
|
}
|
|
|
|
include->parent = this;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TIKI_Error( "^~^~^ Cannot find include file '%s' in %s on line %d\n", &argument1, Filename(), GetLineNumber() );
|
|
|
|
Uninclude();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( !stricmp( command, "path" ) )
|
|
|
|
{
|
|
|
|
strcpy( path, argument1 );
|
|
|
|
len = strlen( path );
|
|
|
|
|
|
|
|
if( path[ len - 1 ] != '/' &&
|
|
|
|
path[ len - 1 ] != '\\' )
|
|
|
|
{
|
|
|
|
strcat( path, "/" );
|
|
|
|
}
|
|
|
|
|
|
|
|
SkipToEOL();
|
|
|
|
SkipWhiteSpace( crossline );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= Completed
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
qboolean TikiScript::Completed( void )
|
|
|
|
{
|
|
|
|
return script_p >= end_p;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= FindMacro
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
const char *TikiScript::FindMacro( const char *macro )
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for( i = 0; i < nummacros; i++ )
|
|
|
|
{
|
|
|
|
if( !stricmp( macro, macros[ i ].name ) )
|
|
|
|
return macros[ i ].macro;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= SkipNonToken
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void TikiScript::SkipNonToken( qboolean crossline )
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// skip space and comments
|
|
|
|
//
|
|
|
|
SkipWhiteSpace( crossline );
|
|
|
|
while( !error )
|
|
|
|
{
|
|
|
|
if( !AtCommand() )
|
|
|
|
break;
|
|
|
|
if( !ProcessCommand( crossline ) )
|
|
|
|
break;
|
|
|
|
if( include )
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= TokenAvailable
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
qboolean TikiScript::TokenAvailable( qboolean crossline )
|
|
|
|
{
|
|
|
|
if( include )
|
|
|
|
{
|
|
|
|
qboolean ret = include->TokenAvailable( crossline );
|
|
|
|
|
|
|
|
if( ret || !crossline || !include->Completed() )
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
Uninclude();
|
|
|
|
}
|
|
|
|
if( tokenready )
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
while( !SafeCheckOverflow() )
|
|
|
|
{
|
|
|
|
if( *script_p <= TOKENSPACE )
|
|
|
|
{
|
|
|
|
if( *script_p == TOKENEOL )
|
|
|
|
{
|
|
|
|
if( !crossline )
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
line++;
|
|
|
|
}
|
|
|
|
script_p++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( !AtComment() )
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if( AtExtendedComment() )
|
|
|
|
{
|
|
|
|
SkipExtendedComment();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( !crossline )
|
|
|
|
return false;
|
|
|
|
SkipToEOL();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= CommentAvailable
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
qboolean TikiScript::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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= UnGetToken
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void TikiScript::UnGetToken( void )
|
|
|
|
{
|
|
|
|
if( include )
|
|
|
|
{
|
|
|
|
include->UnGetToken();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tokenready = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= AtString
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
qboolean TikiScript::AtString( qboolean crossline )
|
|
|
|
{
|
|
|
|
TikiScript *i;
|
|
|
|
//
|
|
|
|
// skip space
|
|
|
|
//
|
|
|
|
|
|
|
|
i = this;
|
|
|
|
while( 1 )
|
|
|
|
{
|
|
|
|
i->SkipNonToken( crossline );
|
|
|
|
|
|
|
|
if( !i->include )
|
|
|
|
break;
|
|
|
|
|
|
|
|
i = i->include;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ( !i->error ) && ( *i->script_p == '"' );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= GetToken
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
const char *TikiScript::GetToken( qboolean crossline )
|
|
|
|
{
|
|
|
|
TikiScript *i;
|
|
|
|
const char *macro_start;
|
|
|
|
const char *macro_end;
|
|
|
|
char *token_p;
|
|
|
|
int len;
|
|
|
|
const char *subst;
|
|
|
|
char macro[ 256 ];
|
|
|
|
char temptoken[ 256 ];
|
|
|
|
|
|
|
|
i = this;
|
|
|
|
while( 1 )
|
|
|
|
{
|
|
|
|
if( i->include )
|
|
|
|
{
|
|
|
|
const char *ret;
|
|
|
|
|
|
|
|
ret = i->include->GetToken( crossline );
|
|
|
|
|
|
|
|
if( *ret || !crossline || !i->include->Completed() )
|
|
|
|
{
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
i->Uninclude();
|
|
|
|
}
|
|
|
|
|
|
|
|
if( i->tokenready )
|
|
|
|
{
|
|
|
|
i->tokenready = false;
|
|
|
|
currentScript = i;
|
|
|
|
return i->token;
|
|
|
|
}
|
|
|
|
|
|
|
|
i->SkipNonToken( crossline );
|
|
|
|
|
|
|
|
if( i->error )
|
|
|
|
{
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !i->include )
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
i = i->include;
|
|
|
|
}
|
|
|
|
|
|
|
|
token_p = ( char * )i->script_p;
|
|
|
|
|
|
|
|
if( *token_p == '"' )
|
|
|
|
{
|
|
|
|
currentScript = i;
|
|
|
|
return i->GetString( crossline );
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_start = NULL;
|
|
|
|
macro_end = NULL;
|
|
|
|
token_p = i->token;
|
|
|
|
while( ( *i->script_p > TOKENSPACE ) && !i->AtComment() )
|
|
|
|
{
|
|
|
|
if( ( *i->script_p == '\\' ) && ( i->script_p < ( end_p - 1 ) ) )
|
|
|
|
{
|
|
|
|
i->script_p++;
|
|
|
|
switch( *i->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++ = *i->script_p; break;
|
|
|
|
}
|
|
|
|
i->script_p++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( *i->script_p == '$' )
|
|
|
|
{
|
|
|
|
if( macro_start )
|
|
|
|
macro_end = token_p;
|
|
|
|
else
|
|
|
|
macro_start = token_p;
|
|
|
|
}
|
|
|
|
*token_p++ = *i->script_p++;
|
|
|
|
}
|
|
|
|
|
2023-05-21 00:29:26 +02:00
|
|
|
if( token_p == &i->token[ TIKI_MAXTOKEN ] )
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
|
|
|
TIKI_DPrintf( "Token too large on line %i in file %s\n", i->line, i->Filename() );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( i->script_p == i->end_p )
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*token_p = 0;
|
|
|
|
|
|
|
|
if( macro_start )
|
|
|
|
{
|
|
|
|
if( !macro_end ) macro_end = token_p;
|
|
|
|
|
|
|
|
len = ( macro_end - 1 ) - ( macro_start + 1 );
|
|
|
|
if( len == -1 )
|
|
|
|
{
|
|
|
|
if( macro_start - i->token != 0 )
|
|
|
|
memcpy( temptoken, i->token, macro_start - i->token );
|
|
|
|
|
|
|
|
temptoken[ macro_start - i->token ] = '$';
|
|
|
|
temptoken[ macro_start - i->token + 1 ] = 0;
|
|
|
|
if( *( macro_end + 1 ) )
|
|
|
|
{
|
|
|
|
strcat( temptoken, macro_end + 1 );
|
|
|
|
}
|
|
|
|
strcpy( i->token, temptoken );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
memcpy( macro, ( macro_start + 1 ), len + 1 );
|
|
|
|
macro[ len + 1 ] = 0;
|
|
|
|
subst = i->FindMacro( macro );
|
|
|
|
if( subst )
|
|
|
|
{
|
|
|
|
if( macro_start - i->token != 0 )
|
|
|
|
memcpy( temptoken, i->token, macro_start - i->token );
|
|
|
|
|
|
|
|
temptoken[ macro_start - i->token + 1 ] = 0;
|
|
|
|
strcat( temptoken, subst );
|
|
|
|
if( *( macro_end + 1 ) )
|
|
|
|
{
|
|
|
|
strcat( temptoken, macro_end + 1 );
|
|
|
|
}
|
|
|
|
strcpy( i->token, temptoken );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
i->currentScript = i;
|
|
|
|
return i->token;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= GetLine
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
const char *TikiScript::GetLine( qboolean crossline )
|
|
|
|
{
|
|
|
|
TikiScript *i;
|
|
|
|
const char *start;
|
|
|
|
int size;
|
|
|
|
|
|
|
|
i = this;
|
|
|
|
while( 1 )
|
|
|
|
{
|
|
|
|
if( i->include )
|
|
|
|
{
|
|
|
|
const char *ret;
|
|
|
|
|
|
|
|
ret = i->include->GetToken( crossline );
|
|
|
|
|
|
|
|
if( *ret || !crossline || !i->include->Completed() )
|
|
|
|
{
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
i->Uninclude();
|
|
|
|
}
|
|
|
|
|
|
|
|
if( i->tokenready )
|
|
|
|
{
|
|
|
|
i->tokenready = false;
|
|
|
|
return i->token;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !i->include )
|
|
|
|
break;
|
|
|
|
|
|
|
|
i = i->include;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( i->error )
|
|
|
|
{
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// copy token
|
|
|
|
//
|
|
|
|
start = i->script_p;
|
|
|
|
SkipToEOL();
|
|
|
|
size = i->script_p - start;
|
2023-05-21 00:29:26 +02:00
|
|
|
if( size < ( TIKI_MAXTOKEN - 1 ) )
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
|
|
|
memcpy( i->token, start, size );
|
|
|
|
i->token[ size ] = '\0';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TIKI_DPrintf( "Token too large on line %i in file %s\n", i->line, i->filename );
|
|
|
|
}
|
|
|
|
|
|
|
|
return i->token;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= GetAndIgnoreLine
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
const char *TikiScript::GetAndIgnoreLine( qboolean crossline )
|
|
|
|
{
|
|
|
|
const char *start;
|
|
|
|
int size;
|
|
|
|
|
|
|
|
if( include )
|
|
|
|
{
|
|
|
|
const char *ret;
|
|
|
|
|
|
|
|
ret = include->GetAndIgnoreLine( crossline );
|
|
|
|
|
|
|
|
if( *ret || !crossline || !include->Completed() )
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
Uninclude();
|
|
|
|
}
|
|
|
|
|
|
|
|
if( tokenready )
|
|
|
|
{
|
|
|
|
tokenready = false;
|
|
|
|
return token;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// skip space
|
|
|
|
//
|
|
|
|
SkipWhiteSpace( crossline );
|
|
|
|
|
|
|
|
if( error )
|
|
|
|
{
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// copy token
|
|
|
|
//
|
|
|
|
start = script_p;
|
|
|
|
SkipToEOL();
|
|
|
|
size = script_p - start;
|
2023-05-21 00:29:26 +02:00
|
|
|
if( size < ( TIKI_MAXTOKEN - 1 ) )
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
|
|
|
memcpy( token, start, size );
|
|
|
|
token[ size ] = '\0';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TIKI_DPrintf( "Token too large on line %i in file %s\n", line, filename );
|
|
|
|
}
|
|
|
|
|
|
|
|
return token;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= GetRaw
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
const char *TikiScript::GetRaw( void )
|
|
|
|
{
|
|
|
|
const char *start;
|
|
|
|
int size;
|
|
|
|
|
|
|
|
if( include )
|
|
|
|
{
|
|
|
|
const char *ret;
|
|
|
|
|
|
|
|
ret = include->GetRaw();
|
|
|
|
|
|
|
|
if( *ret || !include->Completed() )
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
Uninclude();
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// skip white space
|
|
|
|
//
|
|
|
|
SkipWhiteSpace( true );
|
|
|
|
|
|
|
|
if( error )
|
|
|
|
{
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// copy token
|
|
|
|
//
|
|
|
|
start = script_p;
|
|
|
|
SkipToEOL();
|
|
|
|
size = script_p - start;
|
2023-05-21 00:29:26 +02:00
|
|
|
if( size < ( TIKI_MAXTOKEN - 1 ) )
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
|
|
|
memset( token, 0, sizeof( token ) );
|
|
|
|
memcpy( token, start, size );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TIKI_DPrintf( "Token too large on line %i in file %s\n", line, filename );
|
|
|
|
}
|
|
|
|
|
|
|
|
return token;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= GetString
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
const char *TikiScript::GetString( qboolean crossline )
|
|
|
|
{
|
|
|
|
TikiScript *i;
|
|
|
|
int startline;
|
|
|
|
char *token_p;
|
|
|
|
|
|
|
|
i = this;
|
|
|
|
while( 1 )
|
|
|
|
{
|
|
|
|
if( i->include )
|
|
|
|
{
|
|
|
|
const char *ret;
|
|
|
|
|
|
|
|
ret = i->include->GetString( crossline );
|
|
|
|
|
|
|
|
if( *ret || !crossline || !i->include->Completed() )
|
|
|
|
{
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
i->Uninclude();
|
|
|
|
}
|
|
|
|
|
|
|
|
// is a token already waiting?
|
|
|
|
if( i->tokenready )
|
|
|
|
{
|
|
|
|
i->tokenready = false;
|
|
|
|
return i->token;
|
|
|
|
}
|
|
|
|
|
|
|
|
i->SkipNonToken( crossline );
|
|
|
|
|
|
|
|
if( !i->include )
|
|
|
|
break;
|
|
|
|
|
|
|
|
i = i->include;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( i->error )
|
|
|
|
{
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
if( *i->script_p != '"' )
|
|
|
|
{
|
|
|
|
TIKI_DPrintf( "Expecting string on line %i in file %s\n", i->line, i->filename );
|
|
|
|
return i->token;
|
|
|
|
}
|
|
|
|
|
|
|
|
i->script_p++;
|
|
|
|
|
|
|
|
startline = i->line;
|
|
|
|
token_p = i->token;
|
|
|
|
while( *i->script_p != '"' )
|
|
|
|
{
|
|
|
|
if( *i->script_p == TOKENEOL )
|
|
|
|
{
|
|
|
|
TIKI_DPrintf( "Line %i is incomplete while reading string in file %s\n", i->line, i->filename );
|
|
|
|
return i->token;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( ( *i->script_p == '\\' ) && ( i->script_p < ( end_p - 1 ) ) )
|
|
|
|
{
|
|
|
|
i->script_p++;
|
|
|
|
switch( *i->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++ = *i->script_p; break;
|
|
|
|
}
|
|
|
|
i->script_p++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*token_p++ = *i->script_p++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( i->script_p >= i->end_p )
|
|
|
|
{
|
|
|
|
TIKI_DPrintf( "End of token file reached prematurely while reading string on\n"
|
|
|
|
"line %d in file %s\n", startline, i->filename );
|
|
|
|
}
|
|
|
|
|
2023-05-21 00:29:26 +02:00
|
|
|
if( token_p == &i->token[ TIKI_MAXTOKEN ] )
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
|
|
|
TIKI_DPrintf( "String too large on line %i in file %s\n", i->line, i->filename );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*token_p = 0;
|
|
|
|
|
|
|
|
// skip last quote
|
|
|
|
i->script_p++;
|
|
|
|
|
|
|
|
return i->token;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= GetSpecific
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
qboolean TikiScript::GetSpecific( const char *string )
|
|
|
|
{
|
|
|
|
if( include )
|
|
|
|
{
|
|
|
|
qboolean ret = include->GetSpecific( string );
|
|
|
|
if( ret || !include->Completed() )
|
|
|
|
{
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if( !TokenAvailable( true ) )
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
GetToken( true );
|
|
|
|
} while( strcmp( token, string ) );
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= GetInteger
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
int TikiScript::GetInteger( qboolean crossline )
|
|
|
|
{
|
|
|
|
return atoi( GetToken( crossline ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= GetDouble
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
double TikiScript::GetDouble( qboolean crossline )
|
|
|
|
{
|
|
|
|
return atof( GetToken( crossline ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= GetFloat
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
float TikiScript::GetFloat( qboolean crossline )
|
|
|
|
{
|
|
|
|
return ( float )GetDouble( crossline );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= GetVector
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void TikiScript::GetVector( qboolean crossline, float *vec )
|
|
|
|
{
|
|
|
|
vec[ 0 ] = GetFloat( crossline );
|
|
|
|
vec[ 1 ] = GetFloat( crossline );
|
|
|
|
vec[ 2 ] = GetFloat( crossline );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= LinesInFile
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
int TikiScript::LinesInFile( void )
|
|
|
|
{
|
|
|
|
qboolean temp_tokenready;
|
|
|
|
const char *temp_script_p;
|
|
|
|
int temp_line;
|
2023-05-21 00:29:26 +02:00
|
|
|
char temp_token[ TIKI_MAXTOKEN ];
|
2016-03-27 11:49:47 +02:00
|
|
|
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 TikiScript::Parse( char *data, int length, const char *name )
|
|
|
|
{
|
|
|
|
Close();
|
|
|
|
|
|
|
|
buffer = data;
|
|
|
|
Reset();
|
|
|
|
this->length = length;
|
|
|
|
end_p = script_p + length;
|
2023-05-21 00:29:26 +02:00
|
|
|
strncpy( filename, name, TIKI_MAXTOKEN );
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= LoadFile
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
qboolean TikiScript::LoadFile( const char *name, qboolean quiet )
|
|
|
|
{
|
|
|
|
int length;
|
|
|
|
char *buf;
|
|
|
|
|
|
|
|
Close();
|
|
|
|
|
|
|
|
length = TIKI_ReadFileEx( name, ( void ** )&buf, quiet );
|
|
|
|
|
|
|
|
if( length < 0 )
|
|
|
|
{
|
|
|
|
if( !quiet )
|
|
|
|
TIKI_DPrintf( "Tiki:LoadFile Couldn't load %s\n", name );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// create our own space
|
|
|
|
buffer = ( char * )TIKI_Alloc( length + 1 );
|
|
|
|
// copy the file over to our space
|
|
|
|
memcpy( buffer, buf, length );
|
|
|
|
buffer[ length ] = 0;
|
|
|
|
// free the file
|
|
|
|
TIKI_FreeFile( buf );
|
|
|
|
|
|
|
|
Parse( buffer, length, name );
|
|
|
|
releaseBuffer = true;
|
|
|
|
|
|
|
|
if( error )
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= Token
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
const char *TikiScript::Token( void )
|
|
|
|
{
|
|
|
|
if( include )
|
|
|
|
{
|
|
|
|
return include->token;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return token;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= MarkPos
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void TikiScript::MarkPos( void )
|
|
|
|
{
|
|
|
|
mark[ mark_pos ].mark_script_p = script_p;
|
|
|
|
mark[ mark_pos ].mark_tokenready = tokenready;
|
|
|
|
strcpy( mark[ mark_pos ].mark_token, token );
|
|
|
|
mark_pos++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= ReturnToMark
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void TikiScript::ReturnToMark( void )
|
|
|
|
{
|
|
|
|
if( mark_pos <= 0 )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mark_pos--;
|
|
|
|
script_p = mark[ mark_pos ].mark_script_p;
|
|
|
|
tokenready = mark[ mark_pos ].mark_tokenready;
|
|
|
|
memcpy( token, mark[ mark_pos ].mark_token, sizeof( token ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= ReplaceLineWithWhitespace
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void TikiScript::ReplaceLineWithWhitespace( bool deleteFromStartOfLine )
|
|
|
|
{
|
|
|
|
char *change_p = ( char * )script_p;
|
|
|
|
|
|
|
|
if( deleteFromStartOfLine && *( change_p - 1 ) != '\n' )
|
|
|
|
{
|
|
|
|
while( *( change_p - 1 ) != TOKENEOL && change_p > buffer )
|
|
|
|
{
|
|
|
|
change_p--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( *change_p != TOKENEOL )
|
|
|
|
{
|
|
|
|
if( change_p >= end_p )
|
|
|
|
{
|
|
|
|
script_p = change_p;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
*change_p++ = TOKENSPACE;
|
|
|
|
} while( *change_p != TOKENEOL && change_p < end_p );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( change_p < end_p )
|
|
|
|
{
|
|
|
|
script_p = change_p + 1;
|
|
|
|
line++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
script_p = change_p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
=
|
|
|
|
= GetParentToken
|
|
|
|
=
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
const char *TikiScript::GetParentToken( void )
|
|
|
|
{
|
|
|
|
if( parent )
|
|
|
|
return parent->token;
|
|
|
|
else
|
|
|
|
return "";
|
|
|
|
}
|