2012-09-19 15:15:01 +00:00
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
2017-11-06 04:33:32 +00:00
# include <unordered_map>
2012-09-19 15:15:01 +00:00
# include "platform/platform.h"
# include "console/console.h"
# include "core/tAlgorithm.h"
# include "core/strings/findMatch.h"
# include "console/consoleInternal.h"
# include "core/stream/fileStream.h"
# include "console/engineAPI.h"
//#define DEBUG_SPEW
# define ST_INIT_SIZE 15
static char scratchBuffer [ 1024 ] ;
U32 Namespace : : mCacheSequence = 0 ;
DataChunker Namespace : : mCacheAllocator ;
DataChunker Namespace : : mAllocator ;
Namespace * Namespace : : mNamespaceList = NULL ;
Namespace * Namespace : : mGlobalNamespace = NULL ;
2017-11-06 04:33:32 +00:00
namespace std
{
template < > struct hash < std : : pair < StringTableEntry , StringTableEntry > >
{
typedef std : : pair < StringTableEntry , StringTableEntry > argument_type ;
typedef size_t result_type ;
result_type operator ( ) ( argument_type const & s ) const
{
return HashPointer ( s . first ) ^ ( HashPointer ( s . second ) < < 1 ) ;
}
} ;
} ;
std : : unordered_map < std : : pair < StringTableEntry , StringTableEntry > , Namespace * > gNamespaceCache ;
2012-09-19 15:15:01 +00:00
bool canTabComplete ( const char * prevText , const char * bestMatch ,
2017-11-06 04:33:32 +00:00
const char * newText , S32 baseLen , bool fForward )
2012-09-19 15:15:01 +00:00
{
// test if it matches the first baseLen chars:
2017-11-06 04:33:32 +00:00
if ( dStrnicmp ( newText , prevText , baseLen ) )
2012-09-19 15:15:01 +00:00
return false ;
if ( fForward )
{
2017-11-06 04:33:32 +00:00
if ( ! bestMatch )
2012-09-19 15:15:01 +00:00
return dStricmp ( newText , prevText ) > 0 ;
else
return ( dStricmp ( newText , prevText ) > 0 ) & &
2017-11-06 04:33:32 +00:00
( dStricmp ( newText , bestMatch ) < 0 ) ;
2012-09-19 15:15:01 +00:00
}
else
{
2017-11-06 04:33:32 +00:00
if ( dStrlen ( prevText ) = = ( U32 ) baseLen )
2012-09-19 15:15:01 +00:00
{
// look for the 'worst match'
2017-11-06 04:33:32 +00:00
if ( ! bestMatch )
2012-09-19 15:15:01 +00:00
return dStricmp ( newText , prevText ) > 0 ;
else
return dStricmp ( newText , bestMatch ) > 0 ;
}
else
{
if ( ! bestMatch )
return ( dStricmp ( newText , prevText ) < 0 ) ;
else
return ( dStricmp ( newText , prevText ) < 0 ) & &
2017-11-06 04:33:32 +00:00
( dStricmp ( newText , bestMatch ) > 0 ) ;
2012-09-19 15:15:01 +00:00
}
}
}
//---------------------------------------------------------------
//
// Dictionary functions
//
//---------------------------------------------------------------
struct StringValue
{
S32 size ;
char * val ;
operator char * ( ) { return val ; }
StringValue & operator = ( const char * string ) ;
StringValue ( ) { size = 0 ; val = NULL ; }
~ StringValue ( ) { dFree ( val ) ; }
} ;
StringValue & StringValue : : operator = ( const char * string )
{
2017-11-06 04:33:32 +00:00
if ( ! val )
2012-09-19 15:15:01 +00:00
{
val = dStrdup ( string ) ;
size = dStrlen ( val ) ;
}
else
{
S32 len = dStrlen ( string ) ;
2017-11-06 04:33:32 +00:00
if ( len < size )
2018-03-06 06:59:05 +00:00
dStrcpy ( val , string , size ) ;
2012-09-19 15:15:01 +00:00
else
{
size = len ;
dFree ( val ) ;
val = dStrdup ( string ) ;
}
}
return * this ;
}
2017-11-06 04:33:32 +00:00
static S32 QSORT_CALLBACK varCompare ( const void * a , const void * b )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
return dStricmp ( ( * ( ( Dictionary : : Entry * * ) a ) ) - > name , ( * ( ( Dictionary : : Entry * * ) b ) ) - > name ) ;
2012-09-19 15:15:01 +00:00
}
void Dictionary : : exportVariables ( const char * varString , const char * fileName , bool append )
{
const char * searchStr = varString ;
Vector < Entry * > sortList ( __FILE__ , __LINE__ ) ;
2017-11-06 04:33:32 +00:00
for ( S32 i = 0 ; i < hashTable - > size ; i + + )
2012-09-19 15:15:01 +00:00
{
Entry * walk = hashTable - > data [ i ] ;
2017-11-06 04:33:32 +00:00
while ( walk )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
if ( FindMatch : : isMatch ( ( char * ) searchStr , ( char * ) walk - > name ) )
2012-09-19 15:15:01 +00:00
sortList . push_back ( walk ) ;
walk = walk - > nextEntry ;
}
}
2017-11-06 04:33:32 +00:00
if ( ! sortList . size ( ) )
2012-09-19 15:15:01 +00:00
return ;
2017-11-06 04:33:32 +00:00
dQsort ( ( void * ) & sortList [ 0 ] , sortList . size ( ) , sizeof ( Entry * ) , varCompare ) ;
2012-09-19 15:15:01 +00:00
Vector < Entry * > : : iterator s ;
char expandBuffer [ 1024 ] ;
FileStream * strm = NULL ;
2017-11-06 04:33:32 +00:00
if ( fileName )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
if ( ( strm = FileStream : : createAndOpen ( fileName , append ? Torque : : FS : : File : : ReadWrite : Torque : : FS : : File : : Write ) ) = = NULL )
2012-09-19 15:15:01 +00:00
{
Con : : errorf ( ConsoleLogEntry : : General , " Unable to open file '%s for writing. " , fileName ) ;
return ;
}
2017-11-06 04:33:32 +00:00
if ( append )
2012-09-19 15:15:01 +00:00
strm - > setPosition ( strm - > getStreamSize ( ) ) ;
}
char buffer [ 1024 ] ;
const char * cat = fileName ? " \r \n " : " " ;
2017-11-06 04:33:32 +00:00
for ( s = sortList . begin ( ) ; s ! = sortList . end ( ) ; s + + )
2012-09-19 15:15:01 +00:00
{
2023-06-02 14:36:04 +00:00
switch ( ( * s ) - > value . getType ( ) )
2012-09-19 15:15:01 +00:00
{
2023-06-02 14:36:04 +00:00
case ConsoleValueType : : cvInteger :
dSprintf ( buffer , sizeof ( buffer ) , " %s = %d;%s " , ( * s ) - > name , ( * s ) - > getIntValue ( ) , cat ) ;
2012-09-19 15:15:01 +00:00
break ;
2023-06-02 14:36:04 +00:00
case ConsoleValueType : : cvFloat :
dSprintf ( buffer , sizeof ( buffer ) , " %s = %g;%s " , ( * s ) - > name , ( * s ) - > getFloatValue ( ) , cat ) ;
2012-09-19 15:15:01 +00:00
break ;
default :
expandEscape ( expandBuffer , ( * s ) - > getStringValue ( ) ) ;
dSprintf ( buffer , sizeof ( buffer ) , " %s = \" %s \" ;%s " , ( * s ) - > name , expandBuffer , cat ) ;
break ;
}
2017-11-06 04:33:32 +00:00
if ( strm )
2012-09-19 15:15:01 +00:00
strm - > write ( dStrlen ( buffer ) , buffer ) ;
else
Con : : printf ( " %s " , buffer ) ;
}
2017-11-06 04:33:32 +00:00
if ( strm )
2012-09-19 15:15:01 +00:00
delete strm ;
}
2017-11-06 04:33:32 +00:00
void Dictionary : : exportVariables ( const char * varString , Vector < String > * names , Vector < String > * values )
2012-09-19 15:15:01 +00:00
{
const char * searchStr = varString ;
Vector < Entry * > sortList ( __FILE__ , __LINE__ ) ;
2017-11-06 04:33:32 +00:00
for ( S32 i = 0 ; i < hashTable - > size ; i + + )
2012-09-19 15:15:01 +00:00
{
Entry * walk = hashTable - > data [ i ] ;
2017-11-06 04:33:32 +00:00
while ( walk )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
if ( FindMatch : : isMatch ( ( char * ) searchStr , ( char * ) walk - > name ) )
sortList . push_back ( walk ) ;
2012-09-19 15:15:01 +00:00
walk = walk - > nextEntry ;
}
}
2017-11-06 04:33:32 +00:00
if ( ! sortList . size ( ) )
2012-09-19 15:15:01 +00:00
return ;
2017-11-06 04:33:32 +00:00
dQsort ( ( void * ) & sortList [ 0 ] , sortList . size ( ) , sizeof ( Entry * ) , varCompare ) ;
2012-09-19 15:15:01 +00:00
2017-11-06 04:33:32 +00:00
if ( names )
names - > reserve ( sortList . size ( ) ) ;
if ( values )
values - > reserve ( sortList . size ( ) ) ;
2012-09-19 15:15:01 +00:00
char expandBuffer [ 1024 ] ;
Vector < Entry * > : : iterator s ;
2017-11-06 04:33:32 +00:00
for ( s = sortList . begin ( ) ; s ! = sortList . end ( ) ; s + + )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
if ( names )
names - > push_back ( String ( ( * s ) - > name ) ) ;
2012-09-19 15:15:01 +00:00
2017-11-06 04:33:32 +00:00
if ( values )
2012-09-19 15:15:01 +00:00
{
2023-06-02 14:36:04 +00:00
switch ( ( * s ) - > value . getType ( ) )
2012-09-19 15:15:01 +00:00
{
2021-03-30 23:33:19 +00:00
case ConsoleValueType : : cvInteger :
case ConsoleValueType : : cvFloat :
2021-04-13 01:26:26 +00:00
values - > push_back ( String ( ( * s ) - > getStringValue ( ) ) ) ;
2017-11-06 04:33:32 +00:00
break ;
default :
expandEscape ( expandBuffer , ( * s ) - > getStringValue ( ) ) ;
values - > push_back ( expandBuffer ) ;
break ;
2012-09-19 15:15:01 +00:00
}
}
}
}
void Dictionary : : deleteVariables ( const char * varString )
{
const char * searchStr = varString ;
2017-11-06 04:33:32 +00:00
for ( S32 i = 0 ; i < hashTable - > size ; i + + )
2012-09-19 15:15:01 +00:00
{
Entry * walk = hashTable - > data [ i ] ;
2017-11-06 04:33:32 +00:00
while ( walk )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
Entry * matchedEntry = ( FindMatch : : isMatch ( ( char * ) searchStr , ( char * ) walk - > name ) ) ? walk : NULL ;
2012-09-19 15:15:01 +00:00
walk = walk - > nextEntry ;
if ( matchedEntry )
remove ( matchedEntry ) ; // assumes remove() is a stable remove (will not reorder entries on remove)
}
}
}
2014-09-14 18:44:07 +00:00
U32 HashPointer ( StringTableEntry ptr )
2012-09-19 15:15:01 +00:00
{
2014-09-14 18:44:07 +00:00
return ( U32 ) ( ( ( dsize_t ) ptr ) > > 2 ) ;
2012-09-19 15:15:01 +00:00
}
Dictionary : : Entry * Dictionary : : lookup ( StringTableEntry name )
{
Entry * walk = hashTable - > data [ HashPointer ( name ) % hashTable - > size ] ;
2017-11-06 04:33:32 +00:00
while ( walk )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
if ( walk - > name = = name )
2012-09-19 15:15:01 +00:00
return walk ;
else
walk = walk - > nextEntry ;
}
return NULL ;
}
Dictionary : : Entry * Dictionary : : add ( StringTableEntry name )
{
// Try to find an existing match.
2012-09-23 08:59:48 +00:00
//printf("Add Variable %s\n", name);
2017-11-06 04:33:32 +00:00
Entry * ret = lookup ( name ) ;
if ( ret )
2012-09-19 15:15:01 +00:00
return ret ;
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
// Rehash if the table get's too crowded. Be aware that this might
// modify a table that we don't own.
2017-11-06 04:33:32 +00:00
hashTable - > count + + ;
if ( hashTable - > count > hashTable - > size * 2 )
2012-09-19 15:15:01 +00:00
{
// Allocate a new table.
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
const U32 newTableSize = hashTable - > size * 4 - 1 ;
2017-11-06 04:33:32 +00:00
Entry * * newTableData = new Entry * [ newTableSize ] ;
dMemset ( newTableData , 0 , newTableSize * sizeof ( Entry * ) ) ;
2012-09-19 15:15:01 +00:00
// Move the entries over.
2017-11-06 04:33:32 +00:00
for ( U32 i = 0 ; i < hashTable - > size ; + + i )
for ( Entry * entry = hashTable - > data [ i ] ; entry ! = NULL ; )
2012-09-19 15:15:01 +00:00
{
Entry * next = entry - > nextEntry ;
2017-11-06 04:33:32 +00:00
U32 index = HashPointer ( entry - > name ) % newTableSize ;
entry - > nextEntry = newTableData [ index ] ;
newTableData [ index ] = entry ;
2012-09-19 15:15:01 +00:00
entry = next ;
}
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
// Switch the tables.
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
delete [ ] hashTable - > data ;
hashTable - > data = newTableData ;
hashTable - > size = newTableSize ;
}
2017-11-06 04:33:32 +00:00
# ifdef DEBUG_SPEW
Platform : : outputDebugString ( " [ConsoleInternal] Adding entry '%s' " , name ) ;
# endif
2012-09-19 15:15:01 +00:00
// Add the new entry.
2012-10-11 20:29:39 +00:00
ret = hashTable - > mChunker . alloc ( ) ;
2017-11-06 04:33:32 +00:00
constructInPlace ( ret , name ) ;
2012-09-23 08:59:48 +00:00
U32 idx = HashPointer ( name ) % hashTable - > size ;
2012-09-19 15:15:01 +00:00
ret - > nextEntry = hashTable - > data [ idx ] ;
hashTable - > data [ idx ] = ret ;
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
return ret ;
}
// deleteVariables() assumes remove() is a stable remove (will not reorder entries on remove)
void Dictionary : : remove ( Dictionary : : Entry * ent )
{
Entry * * walk = & hashTable - > data [ HashPointer ( ent - > name ) % hashTable - > size ] ;
2017-11-06 04:33:32 +00:00
while ( * walk ! = ent )
2012-09-19 15:15:01 +00:00
walk = & ( ( * walk ) - > nextEntry ) ;
2017-11-06 04:33:32 +00:00
# ifdef DEBUG_SPEW
Platform : : outputDebugString ( " [ConsoleInternal] Removing entry '%s' " , ent - > name ) ;
# endif
2012-09-19 15:15:01 +00:00
* walk = ( ent - > nextEntry ) ;
2017-11-06 04:33:32 +00:00
hashTable - > mChunker . free ( ent ) ;
2012-09-19 15:15:01 +00:00
hashTable - > count - - ;
}
Dictionary : : Dictionary ( )
2017-11-06 04:33:32 +00:00
: hashTable ( NULL ) ,
2012-09-19 15:15:01 +00:00
# pragma warning( disable : 4355 )
2017-11-06 04:33:32 +00:00
ownHashTable ( this ) , // Warning with VC++ but this is safe.
2012-09-19 15:15:01 +00:00
# pragma warning( default : 4355 )
2017-11-06 04:33:32 +00:00
scopeName ( NULL ) ,
scopeNamespace ( NULL ) ,
2023-04-23 08:39:54 +00:00
module ( NULL ) ,
2017-11-06 04:33:32 +00:00
ip ( 0 )
2012-09-19 15:15:01 +00:00
{
2023-04-23 08:39:54 +00:00
setState ( NULL ) ;
2012-09-19 15:15:01 +00:00
}
2023-04-23 08:39:54 +00:00
void Dictionary : : setState ( Dictionary * ref )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
if ( ref )
2012-09-19 15:15:01 +00:00
{
hashTable = ref - > hashTable ;
return ;
}
2017-11-06 04:33:32 +00:00
if ( ! ownHashTable . data )
2012-09-19 15:15:01 +00:00
{
ownHashTable . count = 0 ;
ownHashTable . size = ST_INIT_SIZE ;
2017-11-06 04:33:32 +00:00
ownHashTable . data = new Entry * [ ownHashTable . size ] ;
dMemset ( ownHashTable . data , 0 , ownHashTable . size * sizeof ( Entry * ) ) ;
2012-09-19 15:15:01 +00:00
}
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
hashTable = & ownHashTable ;
}
Dictionary : : ~ Dictionary ( )
{
reset ( ) ;
2017-11-06 04:33:32 +00:00
if ( ownHashTable . data )
delete [ ] ownHashTable . data ;
2012-09-19 15:15:01 +00:00
}
void Dictionary : : reset ( )
{
2017-11-06 04:33:32 +00:00
if ( hashTable & & hashTable - > owner ! = this )
2012-09-19 15:15:01 +00:00
{
hashTable = NULL ;
return ;
}
2017-11-06 04:33:32 +00:00
for ( U32 i = 0 ; i < ownHashTable . size ; + + i )
2012-09-19 15:15:01 +00:00
{
Entry * walk = ownHashTable . data [ i ] ;
2017-11-06 04:33:32 +00:00
while ( walk )
2012-09-19 15:15:01 +00:00
{
Entry * temp = walk - > nextEntry ;
2017-11-06 04:33:32 +00:00
destructInPlace ( walk ) ;
2012-09-19 15:15:01 +00:00
walk = temp ;
}
}
2017-11-06 04:33:32 +00:00
dMemset ( ownHashTable . data , 0 , ownHashTable . size * sizeof ( Entry * ) ) ;
ownHashTable . mChunker . freeBlocks ( true ) ;
2012-09-19 15:15:01 +00:00
ownHashTable . count = 0 ;
hashTable = NULL ;
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
scopeName = NULL ;
scopeNamespace = NULL ;
2023-04-23 08:39:54 +00:00
module = NULL ;
2012-09-19 15:15:01 +00:00
ip = 0 ;
}
const char * Dictionary : : tabComplete ( const char * prevText , S32 baseLen , bool fForward )
{
S32 i ;
const char * bestMatch = NULL ;
2017-11-06 04:33:32 +00:00
for ( i = 0 ; i < hashTable - > size ; i + + )
2012-09-19 15:15:01 +00:00
{
Entry * walk = hashTable - > data [ i ] ;
2017-11-06 04:33:32 +00:00
while ( walk )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
if ( canTabComplete ( prevText , bestMatch , walk - > name , baseLen , fForward ) )
2012-09-19 15:15:01 +00:00
bestMatch = walk - > name ;
walk = walk - > nextEntry ;
}
}
return bestMatch ;
}
Dictionary : : Entry : : Entry ( StringTableEntry in_name )
{
name = in_name ;
notify = NULL ;
nextEntry = NULL ;
mUsage = NULL ;
mIsConstant = false ;
2020-05-11 19:40:31 +00:00
mNext = NULL ;
2012-09-19 15:15:01 +00:00
}
Dictionary : : Entry : : ~ Entry ( )
{
2021-04-13 01:26:26 +00:00
reset ( ) ;
}
void Dictionary : : Entry : : reset ( )
{
name = NULL ;
2023-06-02 14:36:04 +00:00
value . reset ( ) ;
2017-11-06 04:33:32 +00:00
if ( notify )
2012-09-19 15:15:01 +00:00
delete notify ;
}
const char * Dictionary : : getVariable ( StringTableEntry name , bool * entValid )
{
Entry * ent = lookup ( name ) ;
2017-11-06 04:33:32 +00:00
if ( ent )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
if ( entValid )
2012-09-19 15:15:01 +00:00
* entValid = true ;
return ent - > getStringValue ( ) ;
}
2017-11-06 04:33:32 +00:00
if ( entValid )
2012-09-19 15:15:01 +00:00
* entValid = false ;
// Warn users when they access a variable that isn't defined.
2017-11-06 04:33:32 +00:00
if ( gWarnUndefinedScriptVariables )
2012-09-19 15:15:01 +00:00
Con : : warnf ( " *** Accessed undefined variable '%s' " , name ) ;
return " " ;
}
2012-09-23 08:59:48 +00:00
S32 Dictionary : : getIntVariable ( StringTableEntry name , bool * entValid )
{
2012-10-11 20:29:39 +00:00
Entry * ent = lookup ( name ) ;
2017-11-06 04:33:32 +00:00
if ( ent )
2012-10-11 20:29:39 +00:00
{
2017-11-06 04:33:32 +00:00
if ( entValid )
2012-10-11 20:29:39 +00:00
* entValid = true ;
return ent - > getIntValue ( ) ;
}
2017-11-06 04:33:32 +00:00
if ( entValid )
2012-10-11 20:29:39 +00:00
* entValid = false ;
2012-09-23 08:59:48 +00:00
2017-11-06 04:33:32 +00:00
return 0 ;
2012-09-23 08:59:48 +00:00
}
F32 Dictionary : : getFloatVariable ( StringTableEntry name , bool * entValid )
{
2012-10-11 20:29:39 +00:00
Entry * ent = lookup ( name ) ;
2017-11-06 04:33:32 +00:00
if ( ent )
2012-10-11 20:29:39 +00:00
{
2017-11-06 04:33:32 +00:00
if ( entValid )
2012-10-11 20:29:39 +00:00
* entValid = true ;
return ent - > getFloatValue ( ) ;
}
2012-09-23 08:59:48 +00:00
2017-11-06 04:33:32 +00:00
if ( entValid )
2012-10-11 20:29:39 +00:00
* entValid = false ;
return 0 ;
2012-09-19 15:15:01 +00:00
}
void Dictionary : : setVariable ( StringTableEntry name , const char * value )
{
Entry * ent = add ( name ) ;
2017-11-06 04:33:32 +00:00
if ( ! value )
2012-09-19 15:15:01 +00:00
value = " " ;
ent - > setStringValue ( value ) ;
}
2017-11-06 04:33:32 +00:00
Dictionary : : Entry * Dictionary : : addVariable ( const char * name ,
S32 type ,
void * dataPtr ,
const char * usage )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
AssertFatal ( type > = 0 , " Dictionary::addVariable - Got bad type! " ) ;
2012-09-19 15:15:01 +00:00
2017-11-06 04:33:32 +00:00
if ( name [ 0 ] ! = ' $ ' )
2012-09-19 15:15:01 +00:00
{
scratchBuffer [ 0 ] = ' $ ' ;
2018-03-06 06:59:05 +00:00
dStrcpy ( scratchBuffer + 1 , name , 1023 ) ;
2012-09-19 15:15:01 +00:00
name = scratchBuffer ;
}
Entry * ent = add ( StringTable - > insert ( name ) ) ;
2021-04-13 01:26:26 +00:00
2012-09-19 15:15:01 +00:00
ent - > mUsage = usage ;
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
// Fetch enum table, if any.
2017-11-06 04:33:32 +00:00
ConsoleBaseType * conType = ConsoleBaseType : : getType ( type ) ;
AssertFatal ( conType , " Dictionary::addVariable - invalid console type " ) ;
2023-06-02 14:36:04 +00:00
ent - > value . setConsoleData ( type , dataPtr , conType - > getEnumTable ( ) ) ;
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
return ent ;
}
bool Dictionary : : removeVariable ( StringTableEntry name )
{
2017-11-06 04:33:32 +00:00
if ( Entry * ent = lookup ( name ) )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
remove ( ent ) ;
2012-09-19 15:15:01 +00:00
return true ;
}
return false ;
}
2017-11-06 04:33:32 +00:00
void Dictionary : : addVariableNotify ( const char * name , const Con : : NotifyDelegate & callback )
2012-09-19 15:15:01 +00:00
{
Entry * ent = lookup ( StringTable - > insert ( name ) ) ;
2017-11-06 04:33:32 +00:00
if ( ! ent )
return ;
2012-09-19 15:15:01 +00:00
2017-11-06 04:33:32 +00:00
if ( ! ent - > notify )
2012-10-11 20:29:39 +00:00
ent - > notify = new Entry : : NotifySignal ( ) ;
2012-09-19 15:15:01 +00:00
2017-11-06 04:33:32 +00:00
ent - > notify - > notify ( callback ) ;
2012-09-19 15:15:01 +00:00
}
2017-11-06 04:33:32 +00:00
void Dictionary : : removeVariableNotify ( const char * name , const Con : : NotifyDelegate & callback )
2012-09-19 15:15:01 +00:00
{
Entry * ent = lookup ( StringTable - > insert ( name ) ) ;
2017-11-06 04:33:32 +00:00
if ( ent & & ent - > notify )
ent - > notify - > remove ( callback ) ;
2012-09-19 15:15:01 +00:00
}
void Dictionary : : validate ( )
{
2017-11-06 04:33:32 +00:00
AssertFatal ( ownHashTable . owner = = this ,
" Dictionary::validate() - Dictionary not owner of own hashtable! " ) ;
2012-09-19 15:15:01 +00:00
}
2023-04-23 08:39:54 +00:00
Con : : Module * Con : : findScriptModuleForFile ( const char * fileName )
2017-11-06 04:33:32 +00:00
{
2023-04-23 08:39:54 +00:00
for ( Con : : Module * module : gScriptModules )
2012-09-19 15:15:01 +00:00
{
2023-04-23 08:39:54 +00:00
if ( module - > getName ( ) = = fileName ) {
return module ;
}
2012-09-19 15:15:01 +00:00
}
2023-04-23 08:39:54 +00:00
return NULL ;
2012-09-19 15:15:01 +00:00
}
2017-11-06 04:33:32 +00:00
DefineEngineFunction ( backtrace , void , ( ) , ,
2012-09-19 15:15:01 +00:00
" @brief Prints the scripting call stack to the console log. \n \n "
" Used to trace functions called from within functions. Can help discover what functions were called "
" (and not yet exited) before the current point in scripts. \n \n "
" @ingroup Debugging " )
{
U32 totalSize = 1 ;
2023-04-23 08:39:54 +00:00
for ( U32 i = 0 ; i < Con : : getFrameStack ( ) . size ( ) ; i + + )
2012-09-19 15:15:01 +00:00
{
2023-04-23 08:39:54 +00:00
const Con : : ConsoleFrame * frame = Con : : getStackFrame ( i ) ;
if ( frame - > scopeNamespace & & frame - > scopeNamespace - > mEntryList - > mPackage )
totalSize + = dStrlen ( frame - > scopeNamespace - > mEntryList - > mPackage ) + 2 ;
if ( frame - > scopeName )
totalSize + = dStrlen ( frame - > scopeName ) + 3 ;
if ( frame - > scopeNamespace & & frame - > scopeNamespace - > mName )
totalSize + = dStrlen ( frame - > scopeNamespace - > mName ) + 2 ;
2012-09-19 15:15:01 +00:00
}
char * buf = Con : : getReturnBuffer ( totalSize ) ;
buf [ 0 ] = 0 ;
2023-04-23 08:39:54 +00:00
for ( U32 i = 0 ; i < Con : : getFrameStack ( ) . size ( ) ; i + + )
2012-09-19 15:15:01 +00:00
{
2023-04-23 08:39:54 +00:00
const Con : : ConsoleFrame * frame = Con : : getStackFrame ( i ) ;
2018-03-06 05:48:44 +00:00
dStrcat ( buf , " -> " , totalSize ) ;
2017-11-06 04:33:32 +00:00
2023-04-23 08:39:54 +00:00
if ( frame - > scopeNamespace & & frame - > scopeNamespace - > mEntryList - > mPackage )
2017-11-06 04:33:32 +00:00
{
2018-03-06 05:48:44 +00:00
dStrcat ( buf , " [ " , totalSize ) ;
2023-04-23 08:39:54 +00:00
dStrcat ( buf , frame - > scopeNamespace - > mEntryList - > mPackage , totalSize ) ;
2018-03-06 05:48:44 +00:00
dStrcat ( buf , " ] " , totalSize ) ;
2017-11-06 04:33:32 +00:00
}
2023-04-23 08:39:54 +00:00
if ( frame - > scopeNamespace & & frame - > scopeNamespace - > mName )
2012-09-19 15:15:01 +00:00
{
2023-04-23 08:39:54 +00:00
dStrcat ( buf , frame - > scopeNamespace - > mName , totalSize ) ;
2018-03-06 05:48:44 +00:00
dStrcat ( buf , " :: " , totalSize ) ;
2012-09-19 15:15:01 +00:00
}
2023-04-23 08:39:54 +00:00
if ( frame - > scopeName )
dStrcat ( buf , frame - > scopeName , totalSize ) ;
2012-09-19 15:15:01 +00:00
}
Con : : printf ( " BackTrace: %s " , buf ) ;
}
Namespace : : Entry : : Entry ( )
{
2023-04-23 08:39:54 +00:00
mModule = NULL ;
2012-09-19 15:15:01 +00:00
mType = InvalidFunctionType ;
mUsage = NULL ;
mHeader = NULL ;
mNamespace = NULL ;
2020-05-11 19:40:31 +00:00
cb . mStringCallbackFunc = NULL ;
mFunctionLineNumber = 0 ;
mFunctionName = StringTable - > EmptyString ( ) ;
mFunctionOffset = 0 ;
mMinArgs = 0 ;
mMaxArgs = 0 ;
mNext = NULL ;
mPackage = StringTable - > EmptyString ( ) ;
mToolOnly = false ;
2012-09-19 15:15:01 +00:00
}
void Namespace : : Entry : : clear ( )
{
2023-04-23 08:39:54 +00:00
if ( mModule )
2012-09-19 15:15:01 +00:00
{
2023-04-23 08:39:54 +00:00
mModule - > decRefCount ( ) ;
mModule = NULL ;
2012-09-19 15:15:01 +00:00
}
// Clean up usage strings generated for script functions.
2017-11-06 04:33:32 +00:00
if ( ( mType = = Namespace : : Entry : : ConsoleFunctionType ) & & mUsage )
2012-09-19 15:15:01 +00:00
{
2014-11-07 15:23:16 +00:00
dFree ( mUsage ) ;
2012-09-19 15:15:01 +00:00
mUsage = NULL ;
}
}
Namespace : : Namespace ( )
{
mPackage = NULL ;
mUsage = NULL ;
mCleanUpUsage = false ;
mName = NULL ;
mParent = NULL ;
mNext = NULL ;
mEntryList = NULL ;
mHashSize = 0 ;
mHashTable = 0 ;
mHashSequence = 0 ;
mRefCountToParent = 0 ;
mClassRep = 0 ;
2020-05-11 19:40:31 +00:00
lastUsage = NULL ;
2012-09-19 15:15:01 +00:00
}
Namespace : : ~ Namespace ( )
{
clearEntries ( ) ;
2017-11-06 04:33:32 +00:00
if ( mUsage & & mCleanUpUsage )
2012-09-19 15:15:01 +00:00
{
2014-11-07 15:23:16 +00:00
dFree ( mUsage ) ;
2012-09-19 15:15:01 +00:00
mUsage = NULL ;
mCleanUpUsage = false ;
}
}
void Namespace : : clearEntries ( )
{
2017-11-06 04:33:32 +00:00
for ( Entry * walk = mEntryList ; walk ; walk = walk - > mNext )
2012-09-19 15:15:01 +00:00
walk - > clear ( ) ;
}
Namespace * Namespace : : find ( StringTableEntry name , StringTableEntry package )
{
2017-11-06 04:33:32 +00:00
if ( name = = NULL & & package = = NULL )
2012-09-19 15:15:01 +00:00
return mGlobalNamespace ;
2017-11-06 04:33:32 +00:00
auto pair = std : : make_pair ( name , package ) ;
auto pos = gNamespaceCache . find ( pair ) ;
if ( pos ! = gNamespaceCache . end ( ) )
return pos - > second ;
2012-09-19 15:15:01 +00:00
2017-11-06 04:33:32 +00:00
Namespace * ret = ( Namespace * ) mAllocator . alloc ( sizeof ( Namespace ) ) ;
2012-09-19 15:15:01 +00:00
constructInPlace ( ret ) ;
ret - > mPackage = package ;
ret - > mName = name ;
ret - > mNext = mNamespaceList ;
mNamespaceList = ret ;
2017-11-06 04:33:32 +00:00
// insert into namespace cache.
gNamespaceCache [ pair ] = ret ;
2012-09-19 15:15:01 +00:00
return ret ;
}
2017-11-06 04:33:32 +00:00
bool Namespace : : unlinkClass ( Namespace * parent )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
AssertFatal ( mPackage = = NULL , " Namespace::unlinkClass - Must not be called on a namespace coming from a package! " ) ;
2012-09-19 15:15:01 +00:00
// Skip additions to this namespace coming from packages.
Namespace * walk = getPackageRoot ( ) ;
// Make sure "parent" is the direct parent namespace.
2017-11-06 04:33:32 +00:00
if ( parent ! = NULL & & walk - > mParent & & walk - > mParent ! = parent )
2012-09-19 15:15:01 +00:00
{
Con : : errorf ( ConsoleLogEntry : : General , " Namespace::unlinkClass - cannot unlink namespace parent linkage for %s for %s. " ,
walk - > mName , walk - > mParent - > mName ) ;
return false ;
}
// Decrease the reference count. Note that we do this on
// the bottom-most namespace, i.e. the one guaranteed not
// to come from a package.
2017-11-06 04:33:32 +00:00
mRefCountToParent - - ;
AssertFatal ( mRefCountToParent > = 0 , " Namespace::unlinkClass - reference count to parent is less than 0 " ) ;
2012-09-19 15:15:01 +00:00
// Unlink if the count dropped to zero.
2017-11-06 04:33:32 +00:00
if ( mRefCountToParent = = 0 )
2012-09-19 15:15:01 +00:00
{
walk - > mParent = NULL ;
trashCache ( ) ;
}
return true ;
}
bool Namespace : : classLinkTo ( Namespace * parent )
{
Namespace * walk = getPackageRoot ( ) ;
2017-11-06 04:33:32 +00:00
if ( walk - > mParent & & walk - > mParent ! = parent )
2012-09-19 15:15:01 +00:00
{
Con : : errorf ( ConsoleLogEntry : : General , " Error: cannot change namespace parent linkage of %s from %s to %s. " ,
walk - > mName , walk - > mParent - > mName , parent - > mName ) ;
return false ;
}
trashCache ( ) ;
walk - > mParent = parent ;
mRefCountToParent + + ;
return true ;
}
void Namespace : : buildHashTable ( )
{
2017-11-06 04:33:32 +00:00
if ( mHashSequence = = mCacheSequence )
2012-09-19 15:15:01 +00:00
return ;
2017-11-06 04:33:32 +00:00
if ( ! mEntryList & & mParent )
2012-09-19 15:15:01 +00:00
{
mParent - > buildHashTable ( ) ;
mHashTable = mParent - > mHashTable ;
mHashSize = mParent - > mHashSize ;
mHashSequence = mCacheSequence ;
return ;
}
U32 entryCount = 0 ;
Namespace * ns ;
2017-11-06 04:33:32 +00:00
for ( ns = this ; ns ; ns = ns - > mParent )
for ( Entry * walk = ns - > mEntryList ; walk ; walk = walk - > mNext )
if ( lookupRecursive ( walk - > mFunctionName ) = = walk )
2012-09-19 15:15:01 +00:00
entryCount + + ;
mHashSize = entryCount + ( entryCount > > 1 ) + 1 ;
2017-11-06 04:33:32 +00:00
if ( ! ( mHashSize & 1 ) )
2012-09-19 15:15:01 +00:00
mHashSize + + ;
2017-11-06 04:33:32 +00:00
mHashTable = ( Entry * * ) mCacheAllocator . alloc ( sizeof ( Entry * ) * mHashSize ) ;
for ( U32 i = 0 ; i < mHashSize ; i + + )
2012-09-19 15:15:01 +00:00
mHashTable [ i ] = NULL ;
2017-11-06 04:33:32 +00:00
for ( ns = this ; ns ; ns = ns - > mParent )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
for ( Entry * walk = ns - > mEntryList ; walk ; walk = walk - > mNext )
2012-09-19 15:15:01 +00:00
{
U32 index = HashPointer ( walk - > mFunctionName ) % mHashSize ;
2017-11-06 04:33:32 +00:00
while ( mHashTable [ index ] & & mHashTable [ index ] - > mFunctionName ! = walk - > mFunctionName )
2012-09-19 15:15:01 +00:00
{
index + + ;
2017-11-06 04:33:32 +00:00
if ( index > = mHashSize )
2012-09-19 15:15:01 +00:00
index = 0 ;
}
2017-11-06 04:33:32 +00:00
if ( ! mHashTable [ index ] )
2012-09-19 15:15:01 +00:00
mHashTable [ index ] = walk ;
}
}
mHashSequence = mCacheSequence ;
}
2017-11-06 04:33:32 +00:00
void Namespace : : getUniqueEntryLists ( Namespace * other , VectorPtr < Entry * > * outThisList , VectorPtr < Entry * > * outOtherList )
2012-09-19 15:15:01 +00:00
{
// All namespace entries in the common ACR should be
// ignored when checking for duplicate entry names.
static VectorPtr < Namespace : : Entry * > commonEntries ;
commonEntries . clear ( ) ;
2017-11-06 04:33:32 +00:00
AbstractClassRep * commonACR = mClassRep - > getCommonParent ( other - > mClassRep ) ;
commonACR - > getNameSpace ( ) - > getEntryList ( & commonEntries ) ;
2012-09-19 15:15:01 +00:00
// Make life easier
VectorPtr < Namespace : : Entry * > & thisEntries = * outThisList ;
VectorPtr < Namespace : : Entry * > & compEntries = * outOtherList ;
// Clear, just in case they aren't
thisEntries . clear ( ) ;
compEntries . clear ( ) ;
2017-11-06 04:33:32 +00:00
getEntryList ( & thisEntries ) ;
other - > getEntryList ( & compEntries ) ;
2012-09-19 15:15:01 +00:00
// Run through all of the entries in the common ACR, and remove them from
// the other two entry lists
2017-11-06 04:33:32 +00:00
for ( NamespaceEntryListIterator itr = commonEntries . begin ( ) ; itr ! = commonEntries . end ( ) ; itr + + )
2012-09-19 15:15:01 +00:00
{
// Check this entry list
2017-11-06 04:33:32 +00:00
for ( NamespaceEntryListIterator thisItr = thisEntries . begin ( ) ; thisItr ! = thisEntries . end ( ) ; thisItr + + )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
if ( * thisItr = = * itr )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
thisEntries . erase ( thisItr ) ;
2012-09-19 15:15:01 +00:00
break ;
}
}
// Same check for component entry list
2017-11-06 04:33:32 +00:00
for ( NamespaceEntryListIterator compItr = compEntries . begin ( ) ; compItr ! = compEntries . end ( ) ; compItr + + )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
if ( * compItr = = * itr )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
compEntries . erase ( compItr ) ;
2012-09-19 15:15:01 +00:00
break ;
}
}
}
}
void Namespace : : init ( )
{
// create the global namespace
2017-11-06 04:33:32 +00:00
mGlobalNamespace = ( Namespace * ) mAllocator . alloc ( sizeof ( Namespace ) ) ;
2012-09-19 15:15:01 +00:00
constructInPlace ( mGlobalNamespace ) ;
mGlobalNamespace - > mPackage = NULL ;
mGlobalNamespace - > mName = NULL ;
mGlobalNamespace - > mNext = NULL ;
mNamespaceList = mGlobalNamespace ;
2017-11-06 04:33:32 +00:00
// Insert into namespace cache.
gNamespaceCache [ std : : make_pair ( mGlobalNamespace - > mName , mGlobalNamespace - > mPackage ) ] = mGlobalNamespace ;
2012-09-19 15:15:01 +00:00
}
Namespace * Namespace : : global ( )
{
return mGlobalNamespace ;
}
void Namespace : : shutdown ( )
{
// The data chunker will release all memory in one go
// without calling destructors, so we do this manually here.
2017-11-06 04:33:32 +00:00
for ( Namespace * walk = mNamespaceList ; walk ; walk = walk - > mNext )
2012-09-19 15:15:01 +00:00
walk - > ~ Namespace ( ) ;
2025-05-05 10:06:20 +00:00
gNamespaceCache . clear ( ) ;
mNamespaceList = nullptr ;
mGlobalNamespace = nullptr ;
mAllocator . freeBlocks ( ) ;
2012-09-19 15:15:01 +00:00
}
void Namespace : : trashCache ( )
{
mCacheSequence + + ;
mCacheAllocator . freeBlocks ( ) ;
}
const char * Namespace : : tabComplete ( const char * prevText , S32 baseLen , bool fForward )
{
2017-11-06 04:33:32 +00:00
if ( mHashSequence ! = mCacheSequence )
2012-09-19 15:15:01 +00:00
buildHashTable ( ) ;
const char * bestMatch = NULL ;
2017-11-06 04:33:32 +00:00
for ( U32 i = 0 ; i < mHashSize ; i + + )
if ( mHashTable [ i ] & & canTabComplete ( prevText , bestMatch , mHashTable [ i ] - > mFunctionName , baseLen , fForward ) )
2012-09-19 15:15:01 +00:00
bestMatch = mHashTable [ i ] - > mFunctionName ;
return bestMatch ;
}
Namespace : : Entry * Namespace : : lookupRecursive ( StringTableEntry name )
{
2017-11-06 04:33:32 +00:00
for ( Namespace * ns = this ; ns ; ns = ns - > mParent )
for ( Entry * walk = ns - > mEntryList ; walk ; walk = walk - > mNext )
if ( walk - > mFunctionName = = name )
2012-09-19 15:15:01 +00:00
return walk ;
return NULL ;
}
Namespace : : Entry * Namespace : : lookup ( StringTableEntry name )
{
2017-11-06 04:33:32 +00:00
if ( mHashSequence ! = mCacheSequence )
2012-09-19 15:15:01 +00:00
buildHashTable ( ) ;
U32 index = HashPointer ( name ) % mHashSize ;
2017-11-06 04:33:32 +00:00
while ( mHashTable [ index ] & & mHashTable [ index ] - > mFunctionName ! = name )
2012-09-19 15:15:01 +00:00
{
index + + ;
2017-11-06 04:33:32 +00:00
if ( index > = mHashSize )
2012-09-19 15:15:01 +00:00
index = 0 ;
}
return mHashTable [ index ] ;
}
2017-11-06 04:33:32 +00:00
static S32 QSORT_CALLBACK compareEntries ( const void * a , const void * b )
2012-09-19 15:15:01 +00:00
{
const Namespace : : Entry * fa = * ( ( Namespace : : Entry * * ) a ) ;
const Namespace : : Entry * fb = * ( ( Namespace : : Entry * * ) b ) ;
return dStricmp ( fa - > mFunctionName , fb - > mFunctionName ) ;
}
void Namespace : : getEntryList ( VectorPtr < Entry * > * vec )
{
2017-11-06 04:33:32 +00:00
if ( mHashSequence ! = mCacheSequence )
2012-09-19 15:15:01 +00:00
buildHashTable ( ) ;
2017-11-06 04:33:32 +00:00
for ( U32 i = 0 ; i < mHashSize ; i + + )
if ( mHashTable [ i ] )
2012-09-19 15:15:01 +00:00
vec - > push_back ( mHashTable [ i ] ) ;
2017-11-06 04:33:32 +00:00
dQsort ( vec - > address ( ) , vec - > size ( ) , sizeof ( Namespace : : Entry * ) , compareEntries ) ;
2012-09-19 15:15:01 +00:00
}
Namespace : : Entry * Namespace : : createLocalEntry ( StringTableEntry name )
{
2017-11-06 04:33:32 +00:00
for ( Entry * walk = mEntryList ; walk ; walk = walk - > mNext )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
if ( walk - > mFunctionName = = name )
2012-09-19 15:15:01 +00:00
{
walk - > clear ( ) ;
return walk ;
}
}
2017-11-06 04:33:32 +00:00
Entry * ent = ( Entry * ) mAllocator . alloc ( sizeof ( Entry ) ) ;
2012-09-19 15:15:01 +00:00
constructInPlace ( ent ) ;
ent - > mNamespace = this ;
ent - > mFunctionName = name ;
ent - > mNext = mEntryList ;
ent - > mPackage = mPackage ;
ent - > mToolOnly = false ;
mEntryList = ent ;
return ent ;
}
2023-04-23 08:39:54 +00:00
void Namespace : : addFunction ( StringTableEntry name , Con : : Module * cb , U32 functionOffset , const char * usage , U32 lineNumber )
2012-09-19 15:15:01 +00:00
{
Entry * ent = createLocalEntry ( name ) ;
trashCache ( ) ;
ent - > mUsage = usage ;
2023-04-23 08:39:54 +00:00
ent - > mModule = cb ;
2012-09-19 15:15:01 +00:00
ent - > mFunctionOffset = functionOffset ;
2023-04-23 08:39:54 +00:00
ent - > mModule - > incRefCount ( ) ;
2012-09-19 15:15:01 +00:00
ent - > mType = Entry : : ConsoleFunctionType ;
2017-11-06 04:33:32 +00:00
ent - > mFunctionLineNumber = lineNumber ;
2012-09-19 15:15:01 +00:00
}
2017-11-06 04:33:32 +00:00
void Namespace : : addCommand ( StringTableEntry name , StringCallback cb , const char * usage , S32 minArgs , S32 maxArgs , bool isToolOnly , ConsoleFunctionHeader * header )
2012-09-19 15:15:01 +00:00
{
Entry * ent = createLocalEntry ( name ) ;
trashCache ( ) ;
ent - > mUsage = usage ;
ent - > mHeader = header ;
ent - > mMinArgs = minArgs ;
ent - > mMaxArgs = maxArgs ;
ent - > mToolOnly = isToolOnly ;
ent - > mType = Entry : : StringCallbackType ;
ent - > cb . mStringCallbackFunc = cb ;
}
2017-11-06 04:33:32 +00:00
void Namespace : : addCommand ( StringTableEntry name , IntCallback cb , const char * usage , S32 minArgs , S32 maxArgs , bool isToolOnly , ConsoleFunctionHeader * header )
2012-09-19 15:15:01 +00:00
{
Entry * ent = createLocalEntry ( name ) ;
trashCache ( ) ;
ent - > mUsage = usage ;
ent - > mHeader = header ;
ent - > mMinArgs = minArgs ;
ent - > mMaxArgs = maxArgs ;
ent - > mToolOnly = isToolOnly ;
ent - > mType = Entry : : IntCallbackType ;
ent - > cb . mIntCallbackFunc = cb ;
}
2017-11-06 04:33:32 +00:00
void Namespace : : addCommand ( StringTableEntry name , VoidCallback cb , const char * usage , S32 minArgs , S32 maxArgs , bool isToolOnly , ConsoleFunctionHeader * header )
2012-09-19 15:15:01 +00:00
{
Entry * ent = createLocalEntry ( name ) ;
trashCache ( ) ;
ent - > mUsage = usage ;
ent - > mHeader = header ;
ent - > mMinArgs = minArgs ;
ent - > mMaxArgs = maxArgs ;
ent - > mToolOnly = isToolOnly ;
ent - > mType = Entry : : VoidCallbackType ;
ent - > cb . mVoidCallbackFunc = cb ;
}
2017-11-06 04:33:32 +00:00
void Namespace : : addCommand ( StringTableEntry name , FloatCallback cb , const char * usage , S32 minArgs , S32 maxArgs , bool isToolOnly , ConsoleFunctionHeader * header )
2012-09-19 15:15:01 +00:00
{
Entry * ent = createLocalEntry ( name ) ;
trashCache ( ) ;
ent - > mUsage = usage ;
ent - > mHeader = header ;
ent - > mMinArgs = minArgs ;
ent - > mMaxArgs = maxArgs ;
ent - > mToolOnly = isToolOnly ;
ent - > mType = Entry : : FloatCallbackType ;
ent - > cb . mFloatCallbackFunc = cb ;
}
2017-11-06 04:33:32 +00:00
void Namespace : : addCommand ( StringTableEntry name , BoolCallback cb , const char * usage , S32 minArgs , S32 maxArgs , bool isToolOnly , ConsoleFunctionHeader * header )
2012-09-19 15:15:01 +00:00
{
Entry * ent = createLocalEntry ( name ) ;
trashCache ( ) ;
ent - > mUsage = usage ;
ent - > mHeader = header ;
ent - > mMinArgs = minArgs ;
ent - > mMaxArgs = maxArgs ;
ent - > mToolOnly = isToolOnly ;
ent - > mType = Entry : : BoolCallbackType ;
ent - > cb . mBoolCallbackFunc = cb ;
}
2017-11-06 04:33:32 +00:00
void Namespace : : addScriptCallback ( const char * funcName , const char * usage , ConsoleFunctionHeader * header )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
static U32 uid = 0 ;
2012-09-19 15:15:01 +00:00
char buffer [ 1024 ] ;
char lilBuffer [ 32 ] ;
2018-03-06 06:59:05 +00:00
dStrcpy ( buffer , funcName , 1024 ) ;
2012-09-19 15:15:01 +00:00
dSprintf ( lilBuffer , 32 , " _%d_cb " , uid + + ) ;
2018-03-06 05:48:44 +00:00
dStrcat ( buffer , lilBuffer , 1024 ) ;
2012-09-19 15:15:01 +00:00
2017-11-06 04:33:32 +00:00
Entry * ent = createLocalEntry ( StringTable - > insert ( buffer ) ) ;
2012-09-19 15:15:01 +00:00
trashCache ( ) ;
ent - > mUsage = usage ;
ent - > mHeader = header ;
ent - > mMinArgs = - 2 ;
ent - > mMaxArgs = - 3 ;
ent - > mType = Entry : : ScriptCallbackType ;
ent - > cb . mCallbackName = funcName ;
}
void Namespace : : markGroup ( const char * name , const char * usage )
{
2017-11-06 04:33:32 +00:00
static U32 uid = 0 ;
2012-09-19 15:15:01 +00:00
char buffer [ 1024 ] ;
char lilBuffer [ 32 ] ;
2018-03-06 06:59:05 +00:00
dStrcpy ( buffer , name , 1024 ) ;
2012-09-19 15:15:01 +00:00
dSprintf ( lilBuffer , 32 , " _%d " , uid + + ) ;
2018-03-06 05:48:44 +00:00
dStrcat ( buffer , lilBuffer , 1024 ) ;
2012-09-19 15:15:01 +00:00
2017-11-06 04:33:32 +00:00
Entry * ent = createLocalEntry ( StringTable - > insert ( buffer ) ) ;
2012-09-19 15:15:01 +00:00
trashCache ( ) ;
2017-11-06 04:33:32 +00:00
if ( usage ! = NULL )
2012-09-19 15:15:01 +00:00
lastUsage = ( char * ) ( ent - > mUsage = usage ) ;
else
ent - > mUsage = lastUsage ;
ent - > mMinArgs = - 1 ; // Make sure it explodes if somehow we run this entry.
ent - > mMaxArgs = - 2 ;
ent - > mType = Entry : : GroupMarker ;
ent - > cb . mGroupName = name ;
}
2023-04-23 08:39:54 +00:00
ConsoleValue Namespace : : Entry : : execute ( S32 argc , ConsoleValue * argv , SimObject * thisObj )
2012-09-19 15:15:01 +00:00
{
2015-02-07 22:41:54 +00:00
STR . clearFunctionOffset ( ) ;
2017-11-06 04:33:32 +00:00
if ( mType = = ConsoleFunctionType )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
if ( mFunctionOffset )
2015-02-07 22:41:54 +00:00
{
2023-04-23 08:39:54 +00:00
return std : : move ( mModule - > exec ( mFunctionOffset , argv [ 0 ] . getString ( ) , mNamespace , argc , argv , false , mPackage ) . value ) ;
2015-02-07 22:41:54 +00:00
}
2012-09-19 15:15:01 +00:00
else
2015-02-07 22:41:54 +00:00
{
2025-05-07 16:04:55 +00:00
return ( ConsoleValue ( ) ) ;
2015-02-07 22:41:54 +00:00
}
2012-09-19 15:15:01 +00:00
}
# ifndef TORQUE_DEBUG
// [tom, 12/13/2006] This stops tools functions from working in the console,
// which is useful behavior when debugging so I'm ifdefing this out for debug builds.
2017-11-06 04:33:32 +00:00
if ( mToolOnly & & ! Con : : isCurrentScriptToolScript ( ) )
2012-09-19 15:15:01 +00:00
{
Con : : errorf ( ConsoleLogEntry : : Script , " %s::%s - attempting to call tools only function from outside of tools " , mNamespace - > mName , mFunctionName ) ;
2021-04-01 01:09:23 +00:00
return std : : move ( ConsoleValue ( ) ) ;
2012-09-19 15:15:01 +00:00
}
# endif
2017-11-06 04:33:32 +00:00
if ( ( mMinArgs & & argc < mMinArgs ) | | ( mMaxArgs & & argc > mMaxArgs ) )
2012-09-19 15:15:01 +00:00
{
2024-05-01 23:20:14 +00:00
Con : : warnf ( ConsoleLogEntry : : Script , " %s::%s - wrong number of arguments. got %d, expected %d to %d " , mNamespace - > mName , mFunctionName , argc , mMinArgs , mMaxArgs ) ;
2012-09-19 15:15:01 +00:00
Con : : warnf ( ConsoleLogEntry : : Script , " usage: %s " , mUsage ) ;
2025-05-07 16:04:55 +00:00
return ( ConsoleValue ( ) ) ;
2012-09-19 15:15:01 +00:00
}
2021-04-01 01:09:23 +00:00
ConsoleValue result ;
2017-11-06 04:33:32 +00:00
switch ( mType )
2012-09-19 15:15:01 +00:00
{
case StringCallbackType :
2021-04-01 02:10:55 +00:00
{
2023-04-23 08:39:54 +00:00
const char * str = cb . mStringCallbackFunc ( thisObj , argc , argv ) ;
2021-04-02 04:57:49 +00:00
result . setString ( str ) ;
2021-04-01 01:09:23 +00:00
break ;
2021-04-01 02:10:55 +00:00
}
2012-09-19 15:15:01 +00:00
case IntCallbackType :
2023-04-23 08:39:54 +00:00
result . setInt ( cb . mIntCallbackFunc ( thisObj , argc , argv ) ) ;
2021-04-01 01:09:23 +00:00
break ;
2012-09-19 15:15:01 +00:00
case FloatCallbackType :
2023-04-23 08:39:54 +00:00
result . setFloat ( cb . mFloatCallbackFunc ( thisObj , argc , argv ) ) ;
2021-04-01 01:09:23 +00:00
break ;
2012-09-19 15:15:01 +00:00
case VoidCallbackType :
2023-04-23 08:39:54 +00:00
cb . mVoidCallbackFunc ( thisObj , argc , argv ) ;
2021-04-01 01:09:23 +00:00
break ;
2012-09-19 15:15:01 +00:00
case BoolCallbackType :
2023-04-23 08:39:54 +00:00
result . setBool ( cb . mBoolCallbackFunc ( thisObj , argc , argv ) ) ;
2021-04-01 01:09:23 +00:00
break ;
2012-09-19 15:15:01 +00:00
}
2017-11-06 04:33:32 +00:00
2024-01-03 00:15:21 +00:00
return result ;
2012-09-19 15:15:01 +00:00
}
//-----------------------------------------------------------------------------
// Doc string code.
namespace {
/// Scan the given usage string for an argument list description. With the
/// old console macros, these were usually included as the first part of the
/// usage string.
2017-11-06 04:33:32 +00:00
bool sFindArgumentListSubstring ( const char * usage , const char * & start , const char * & end )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
if ( ! usage )
2012-09-19 15:15:01 +00:00
return false ;
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
const char * ptr = usage ;
2017-11-06 04:33:32 +00:00
while ( * ptr & & * ptr ! = ' ( ' & & * ptr ! = ' \n ' ) // Only scan first line of usage string.
2012-09-19 15:15:01 +00:00
{
// Stop on the first alphanumeric character as we expect
// argument lists to precede descriptions.
2017-11-06 04:33:32 +00:00
if ( dIsalnum ( * ptr ) )
2012-09-19 15:15:01 +00:00
return false ;
2017-11-06 04:33:32 +00:00
ptr + + ;
2012-09-19 15:15:01 +00:00
}
2017-11-06 04:33:32 +00:00
if ( * ptr ! = ' ( ' )
2012-09-19 15:15:01 +00:00
return false ;
start = ptr ;
2017-11-06 04:33:32 +00:00
ptr + + ;
2012-09-19 15:15:01 +00:00
bool inString = false ;
U32 nestingCount = 0 ;
2017-11-06 04:33:32 +00:00
while ( * ptr & & ( * ptr ! = ' ) ' | | nestingCount > 0 | | inString ) )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
if ( * ptr = = ' ( ' )
nestingCount + + ;
else if ( * ptr = = ' ) ' )
nestingCount - - ;
else if ( * ptr = = ' " ' )
2012-09-19 15:15:01 +00:00
inString = ! inString ;
2017-11-06 04:33:32 +00:00
else if ( * ptr = = ' \\ ' & & ptr [ 1 ] = = ' " ' )
ptr + + ;
ptr + + ;
2012-09-19 15:15:01 +00:00
}
2017-11-06 04:33:32 +00:00
if ( * ptr )
ptr + + ;
2012-09-19 15:15:01 +00:00
end = ptr ;
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
return true ;
}
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
///
2017-11-06 04:33:32 +00:00
void sParseList ( const char * str , Vector < String > & outList )
2012-09-19 15:15:01 +00:00
{
// Skip the initial '( '.
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
const char * ptr = str ;
2017-11-06 04:33:32 +00:00
while ( * ptr & & dIsspace ( * ptr ) )
ptr + + ;
if ( * ptr = = ' ( ' )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
ptr + + ;
while ( * ptr & & dIsspace ( * ptr ) )
ptr + + ;
2012-09-19 15:15:01 +00:00
}
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
// Parse out list items.
2017-11-06 04:33:32 +00:00
while ( * ptr & & * ptr ! = ' ) ' )
2012-09-19 15:15:01 +00:00
{
// Find end of element.
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
const char * start = ptr ;
bool inString = false ;
U32 nestingCount = 0 ;
2017-11-06 04:33:32 +00:00
while ( * ptr & & ( ( * ptr ! = ' ) ' & & * ptr ! = ' , ' ) | | nestingCount > 0 | | inString ) )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
if ( * ptr = = ' ( ' )
nestingCount + + ;
else if ( * ptr = = ' ) ' )
nestingCount - - ;
else if ( * ptr = = ' " ' )
2012-09-19 15:15:01 +00:00
inString = ! inString ;
2017-11-06 04:33:32 +00:00
else if ( * ptr = = ' \\ ' & & ptr [ 1 ] = = ' " ' )
ptr + + ;
ptr + + ;
2012-09-19 15:15:01 +00:00
}
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
// Backtrack to remove trailing whitespace.
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
const char * end = ptr ;
2017-11-06 04:33:32 +00:00
if ( * end = = ' , ' | | * end = = ' ) ' )
end - - ;
while ( end > start & & dIsspace ( * end ) )
end - - ;
if ( * end )
end + + ;
2012-09-19 15:15:01 +00:00
// Add to list.
2017-11-06 04:33:32 +00:00
if ( start ! = end )
outList . push_back ( String ( start , end - start ) ) ;
2012-09-19 15:15:01 +00:00
// Skip comma and whitespace.
2017-11-06 04:33:32 +00:00
if ( * ptr = = ' , ' )
ptr + + ;
while ( * ptr & & dIsspace ( * ptr ) )
ptr + + ;
2012-09-19 15:15:01 +00:00
}
}
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
///
2017-11-06 04:33:32 +00:00
void sGetArgNameAndType ( const String & str , String & outType , String & outName )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
if ( ! str . length ( ) )
2012-09-19 15:15:01 +00:00
{
outType = String : : EmptyString ;
outName = String : : EmptyString ;
return ;
}
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
// Find first non-ID character from right.
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
S32 index = str . length ( ) - 1 ;
2017-11-06 04:33:32 +00:00
while ( index > = 0 & & ( dIsalnum ( str [ index ] ) | | str [ index ] = = ' _ ' ) )
index - - ;
2012-09-19 15:15:01 +00:00
const U32 nameStartIndex = index + 1 ;
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
// Find end of type name by skipping rightmost whitespace inwards.
2017-11-06 04:33:32 +00:00
while ( index > = 0 & & dIsspace ( str [ index ] ) )
index - - ;
2012-09-19 15:15:01 +00:00
//
2017-11-06 04:33:32 +00:00
outName = String ( & ( ( const char * ) str ) [ nameStartIndex ] ) ;
outType = String ( str , index + 1 ) ;
2012-09-19 15:15:01 +00:00
}
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
/// Return the type name to show in documentation for the given C++ type.
2017-11-06 04:33:32 +00:00
const char * sGetDocTypeString ( const char * nativeType )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
if ( dStrncmp ( nativeType , " const " , 6 ) = = 0 )
2012-09-19 15:15:01 +00:00
nativeType + = 6 ;
2020-10-03 12:37:55 +00:00
if ( String : : compare ( nativeType , " char* " ) = = 0 | | String : : compare ( nativeType , " char * " ) = = 0 )
2012-09-19 15:15:01 +00:00
return " string " ;
2020-10-03 12:37:55 +00:00
else if ( String : : compare ( nativeType , " S32 " ) = = 0 )
2012-09-19 15:15:01 +00:00
return " int " ;
2020-10-03 12:37:55 +00:00
else if ( String : : compare ( nativeType , " U32 " ) = = 0 )
2017-12-08 19:50:44 +00:00
return " uint " ;
2020-10-03 12:37:55 +00:00
else if ( String : : compare ( nativeType , " F32 " ) = = 0 )
2012-09-19 15:15:01 +00:00
return " float " ;
2017-11-06 04:33:32 +00:00
const U32 length = dStrlen ( nativeType ) ;
if ( nativeType [ length - 1 ] = = ' & ' | | nativeType [ length - 1 ] = = ' * ' )
return StringTable - > insertn ( nativeType , length - 1 ) ;
2012-09-19 15:15:01 +00:00
return nativeType ;
}
}
2017-11-06 04:33:32 +00:00
String Namespace : : Entry : : getBriefDescription ( String * outRemainingDocText ) const
2012-09-19 15:15:01 +00:00
{
String docString = getDocString ( ) ;
2017-11-06 04:33:32 +00:00
S32 newline = docString . find ( ' \n ' ) ;
if ( newline = = - 1 )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
if ( outRemainingDocText )
2012-09-19 15:15:01 +00:00
* outRemainingDocText = String ( ) ;
return docString ;
}
2017-11-06 04:33:32 +00:00
String brief = docString . substr ( 0 , newline ) ;
if ( outRemainingDocText )
* outRemainingDocText = docString . substr ( newline + 1 ) ;
2012-09-19 15:15:01 +00:00
return brief ;
}
String Namespace : : Entry : : getDocString ( ) const
{
const char * argListStart ;
const char * argListEnd ;
2017-11-06 04:33:32 +00:00
if ( sFindArgumentListSubstring ( mUsage , argListStart , argListEnd ) )
2012-09-19 15:15:01 +00:00
{
// Skip the " - " part present in some old doc strings.
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
const char * ptr = argListEnd ;
2017-11-06 04:33:32 +00:00
while ( * ptr & & dIsspace ( * ptr ) )
ptr + + ;
if ( * ptr = = ' - ' )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
ptr + + ;
while ( * ptr & & dIsspace ( * ptr ) )
ptr + + ;
2012-09-19 15:15:01 +00:00
}
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
return ptr ;
}
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
return mUsage ;
}
String Namespace : : Entry : : getArgumentsString ( ) const
{
StringBuilder str ;
2017-11-06 04:33:32 +00:00
if ( mHeader )
2012-09-19 15:15:01 +00:00
{
// Parse out the argument list string supplied with the extended
// function header and add default arguments as we go.
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
Vector < String > argList ;
Vector < String > defaultArgList ;
2017-11-06 04:33:32 +00:00
sParseList ( mHeader - > mArgString , argList ) ;
sParseList ( mHeader - > mDefaultArgString , defaultArgList ) ;
str . append ( ' ( ' ) ;
2012-09-19 15:15:01 +00:00
const U32 numArgs = argList . size ( ) ;
const U32 numDefaultArgs = defaultArgList . size ( ) ;
const U32 firstDefaultArgIndex = numArgs - numDefaultArgs ;
2017-11-06 04:33:32 +00:00
for ( U32 i = 0 ; i < numArgs ; + + i )
2012-09-19 15:15:01 +00:00
{
// Add separator if not first arg.
2017-11-06 04:33:32 +00:00
if ( i > 0 )
str . append ( ' , ' ) ;
2012-09-19 15:15:01 +00:00
// Add type and name.
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
String name ;
String type ;
2017-11-06 04:33:32 +00:00
sGetArgNameAndType ( argList [ i ] , type , name ) ;
str . append ( ' ' ) ;
str . append ( sGetDocTypeString ( type ) ) ;
str . append ( ' ' ) ;
str . append ( name ) ;
2012-09-19 15:15:01 +00:00
// Add default value, if any.
2017-11-06 04:33:32 +00:00
if ( i > = firstDefaultArgIndex )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
str . append ( ' = ' ) ;
str . append ( defaultArgList [ i - firstDefaultArgIndex ] ) ;
2012-09-19 15:15:01 +00:00
}
}
2017-11-06 04:33:32 +00:00
if ( numArgs > 0 )
str . append ( ' ' ) ;
str . append ( ' ) ' ) ;
2012-09-19 15:15:01 +00:00
}
else
{
// No extended function header. Try to parse out the argument
// list from the usage string.
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
const char * argListStart ;
const char * argListEnd ;
2017-11-06 04:33:32 +00:00
if ( sFindArgumentListSubstring ( mUsage , argListStart , argListEnd ) )
str . append ( argListStart , argListEnd - argListStart ) ;
2023-04-23 08:39:54 +00:00
else if ( mType = = ConsoleFunctionType & & mModule )
2012-09-19 15:15:01 +00:00
{
// This isn't correct but the nonsense console stuff is set up such that all
// functions that have no function bodies are keyed to offset 0 to indicate "no code."
// This loses the association with the original function definition so we can't really
// tell here what the actual prototype is except if we searched though the entire opcode
// stream for the corresponding OP_FUNC_DECL (which would require dealing with the
// variable-size instructions).
2017-11-06 04:33:32 +00:00
if ( ! mFunctionOffset )
2012-09-19 15:15:01 +00:00
return " () " ;
2017-11-06 04:33:32 +00:00
2023-04-23 08:39:54 +00:00
String args = mModule - > getFunctionArgs ( mFunctionName , mFunctionOffset ) ;
2017-11-06 04:33:32 +00:00
if ( args . isEmpty ( ) )
2012-09-19 15:15:01 +00:00
return " () " ;
2017-11-06 04:33:32 +00:00
str . append ( " ( " ) ;
str . append ( args ) ;
str . append ( " ) " ) ;
2012-09-19 15:15:01 +00:00
}
}
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
return str . end ( ) ;
}
String Namespace : : Entry : : getPrototypeString ( ) const
{
StringBuilder str ;
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
// Start with return type.
2017-11-06 04:33:32 +00:00
if ( mHeader & & mHeader - > mReturnString )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
str . append ( sGetDocTypeString ( mHeader - > mReturnString ) ) ;
str . append ( ' ' ) ;
2012-09-19 15:15:01 +00:00
}
else
2017-11-06 04:33:32 +00:00
switch ( mType )
2012-09-19 15:15:01 +00:00
{
case StringCallbackType :
2017-11-06 04:33:32 +00:00
str . append ( " string " ) ;
2012-09-19 15:15:01 +00:00
break ;
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
case IntCallbackType :
2017-11-06 04:33:32 +00:00
str . append ( " int " ) ;
2012-09-19 15:15:01 +00:00
break ;
case FloatCallbackType :
2017-11-06 04:33:32 +00:00
str . append ( " float " ) ;
2012-09-19 15:15:01 +00:00
break ;
case VoidCallbackType :
2017-11-06 04:33:32 +00:00
str . append ( " void " ) ;
2012-09-19 15:15:01 +00:00
break ;
case BoolCallbackType :
2017-11-06 04:33:32 +00:00
str . append ( " bool " ) ;
2012-09-19 15:15:01 +00:00
break ;
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
case ScriptCallbackType :
break ;
}
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
// Add function name and arguments.
2017-11-06 04:33:32 +00:00
if ( mType = = ScriptCallbackType )
str . append ( cb . mCallbackName ) ;
2012-09-19 15:15:01 +00:00
else
2017-11-06 04:33:32 +00:00
str . append ( mFunctionName ) ;
str . append ( getArgumentsString ( ) ) ;
2012-09-19 15:15:01 +00:00
return str . end ( ) ;
}
2023-02-15 23:38:45 +00:00
String Namespace : : Entry : : getPrototypeSig ( ) const
{
StringBuilder str ;
// Add function name and arguments.
if ( mType = = ScriptCallbackType )
str . append ( cb . mCallbackName ) ;
else
str . append ( mFunctionName ) ;
if ( mHeader )
{
Vector < String > argList ;
sParseList ( mHeader - > mArgString , argList ) ;
const U32 numArgs = argList . size ( ) ;
str . append ( " (%this " ) ;
if ( numArgs > 0 )
str . append ( ' , ' ) ;
for ( U32 i = 0 ; i < numArgs ; + + i )
{
// Add separator if not first arg.
String name ;
String type ;
if ( i > 0 )
str . append ( ' , ' ) ;
str . append ( ' % ' ) ;
sGetArgNameAndType ( argList [ i ] , type , name ) ;
str . append ( name ) ;
}
str . append ( ' ) ' ) ;
}
return str . end ( ) ;
}
2012-09-19 15:15:01 +00:00
//-----------------------------------------------------------------------------
StringTableEntry Namespace : : mActivePackages [ Namespace : : MaxActivePackages ] ;
U32 Namespace : : mNumActivePackages = 0 ;
U32 Namespace : : mOldNumActivePackages = 0 ;
bool Namespace : : isPackage ( StringTableEntry name )
{
2017-11-06 04:33:32 +00:00
for ( Namespace * walk = mNamespaceList ; walk ; walk = walk - > mNext )
if ( walk - > mPackage = = name )
2012-09-19 15:15:01 +00:00
return true ;
return false ;
}
U32 Namespace : : getActivePackagesCount ( )
{
return mNumActivePackages ;
}
StringTableEntry Namespace : : getActivePackage ( U32 index )
{
2017-11-06 04:33:32 +00:00
if ( index > = mNumActivePackages )
2012-09-19 15:15:01 +00:00
return StringTable - > EmptyString ( ) ;
return mActivePackages [ index ] ;
}
void Namespace : : activatePackage ( StringTableEntry name )
{
2017-11-06 04:33:32 +00:00
if ( mNumActivePackages = = MaxActivePackages )
2012-09-19 15:15:01 +00:00
{
Con : : printf ( " ActivatePackage(%s) failed - Max package limit reached: %d " , name , MaxActivePackages ) ;
return ;
}
2017-11-06 04:33:32 +00:00
if ( ! name )
2012-09-19 15:15:01 +00:00
return ;
// see if this one's already active
2017-11-06 04:33:32 +00:00
for ( U32 i = 0 ; i < mNumActivePackages ; i + + )
if ( mActivePackages [ i ] = = name )
2012-09-19 15:15:01 +00:00
return ;
// kill the cache
trashCache ( ) ;
// find all the package namespaces...
2017-11-06 04:33:32 +00:00
for ( Namespace * walk = mNamespaceList ; walk ; walk = walk - > mNext )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
if ( walk - > mPackage = = name )
2012-09-19 15:15:01 +00:00
{
Namespace * parent = Namespace : : find ( walk - > mName ) ;
// hook the parent
walk - > mParent = parent - > mParent ;
parent - > mParent = walk ;
// now swap the entries:
Entry * ew ;
2017-11-06 04:33:32 +00:00
for ( ew = parent - > mEntryList ; ew ; ew = ew - > mNext )
2012-09-19 15:15:01 +00:00
ew - > mNamespace = walk ;
2017-11-06 04:33:32 +00:00
for ( ew = walk - > mEntryList ; ew ; ew = ew - > mNext )
2012-09-19 15:15:01 +00:00
ew - > mNamespace = parent ;
ew = walk - > mEntryList ;
walk - > mEntryList = parent - > mEntryList ;
parent - > mEntryList = ew ;
}
}
mActivePackages [ mNumActivePackages + + ] = name ;
}
void Namespace : : deactivatePackage ( StringTableEntry name )
{
U32 oldNumActivePackages = mNumActivePackages ;
// Remove all packages down to the given one
2017-11-06 04:33:32 +00:00
deactivatePackageStack ( name ) ;
2012-09-19 15:15:01 +00:00
// Now add back all packages that followed the given one
2017-11-06 04:33:32 +00:00
if ( ! oldNumActivePackages )
2012-09-19 15:15:01 +00:00
return ;
2017-11-06 04:33:32 +00:00
for ( U32 i = mNumActivePackages + 1 ; i < oldNumActivePackages ; i + + )
2012-09-19 15:15:01 +00:00
activatePackage ( mActivePackages [ i ] ) ;
}
void Namespace : : deactivatePackageStack ( StringTableEntry name )
{
S32 i , j ;
2017-11-06 04:33:32 +00:00
for ( i = 0 ; i < mNumActivePackages ; i + + )
if ( mActivePackages [ i ] = = name )
2012-09-19 15:15:01 +00:00
break ;
2017-11-06 04:33:32 +00:00
if ( i = = mNumActivePackages )
2012-09-19 15:15:01 +00:00
return ;
trashCache ( ) ;
// Remove all packages down to the given one
2017-11-06 04:33:32 +00:00
for ( j = mNumActivePackages - 1 ; j > = i ; j - - )
2012-09-19 15:15:01 +00:00
{
// gotta unlink em in reverse order...
2017-11-06 04:33:32 +00:00
for ( Namespace * walk = mNamespaceList ; walk ; walk = walk - > mNext )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
if ( walk - > mPackage = = mActivePackages [ j ] )
2012-09-19 15:15:01 +00:00
{
Namespace * parent = Namespace : : find ( walk - > mName ) ;
// hook the parent
parent - > mParent = walk - > mParent ;
walk - > mParent = NULL ;
// now swap the entries:
Entry * ew ;
2017-11-06 04:33:32 +00:00
for ( ew = parent - > mEntryList ; ew ; ew = ew - > mNext )
2012-09-19 15:15:01 +00:00
ew - > mNamespace = walk ;
2017-11-06 04:33:32 +00:00
for ( ew = walk - > mEntryList ; ew ; ew = ew - > mNext )
2012-09-19 15:15:01 +00:00
ew - > mNamespace = parent ;
ew = walk - > mEntryList ;
walk - > mEntryList = parent - > mEntryList ;
parent - > mEntryList = ew ;
}
}
}
mNumActivePackages = i ;
}
void Namespace : : unlinkPackages ( )
{
mOldNumActivePackages = mNumActivePackages ;
2017-11-06 04:33:32 +00:00
if ( ! mNumActivePackages )
2012-09-19 15:15:01 +00:00
return ;
deactivatePackageStack ( mActivePackages [ 0 ] ) ;
}
void Namespace : : relinkPackages ( )
{
2017-11-06 04:33:32 +00:00
if ( ! mOldNumActivePackages )
2012-09-19 15:15:01 +00:00
return ;
2017-11-06 04:33:32 +00:00
for ( U32 i = 0 ; i < mOldNumActivePackages ; i + + )
2012-09-19 15:15:01 +00:00
activatePackage ( mActivePackages [ i ] ) ;
}
2017-11-06 04:33:32 +00:00
DefineEngineFunction ( isPackage , bool , ( String identifier ) , ,
2012-09-19 15:15:01 +00:00
" @brief Returns true if the identifier is the name of a declared package. \n \n "
" @ingroup Packages \n " )
{
StringTableEntry name = StringTable - > insert ( identifier . c_str ( ) ) ;
return Namespace : : isPackage ( name ) ;
}
2017-11-06 04:33:32 +00:00
DefineEngineFunction ( activatePackage , void , ( String packageName ) , ,
2012-09-19 15:15:01 +00:00
" @brief Activates an existing package. \n \n "
" The activation occurs by updating the namespace linkage of existing functions and methods. "
" If the package is already activated the function does nothing. \n "
" @ingroup Packages \n " )
{
StringTableEntry name = StringTable - > insert ( packageName . c_str ( ) ) ;
Namespace : : activatePackage ( name ) ;
}
2017-11-06 04:33:32 +00:00
DefineEngineFunction ( deactivatePackage , void , ( String packageName ) , ,
2012-09-19 15:15:01 +00:00
" @brief Deactivates a previously activated package. \n \n "
" The package is deactivated by removing its namespace linkages to any function or method. "
" If there are any packages above this one in the stack they are deactivated as well. "
" If the package is not on the stack this function does nothing. \n "
" @ingroup Packages \n " )
{
StringTableEntry name = StringTable - > insert ( packageName . c_str ( ) ) ;
Namespace : : deactivatePackage ( name ) ;
}
2017-11-06 04:33:32 +00:00
DefineEngineFunction ( getPackageList , const char * , ( ) , ,
2012-09-19 15:15:01 +00:00
" @brief Returns a space delimited list of the active packages in stack order. \n \n "
" @ingroup Packages \n " )
{
2017-11-06 04:33:32 +00:00
if ( Namespace : : getActivePackagesCount ( ) = = 0 )
2012-09-19 15:15:01 +00:00
return " " ;
// Determine size of return buffer
dsize_t buffersize = 0 ;
2017-11-06 04:33:32 +00:00
for ( U32 i = 0 ; i < Namespace : : getActivePackagesCount ( ) ; + + i )
2012-09-19 15:15:01 +00:00
{
buffersize + = dStrlen ( Namespace : : getActivePackage ( i ) ) + 1 ;
}
U32 maxBufferSize = buffersize + 1 ;
char * returnBuffer = Con : : getReturnBuffer ( maxBufferSize ) ;
U32 returnLen = 0 ;
2017-11-06 04:33:32 +00:00
for ( U32 i = 0 ; i < Namespace : : getActivePackagesCount ( ) ; + + i )
2012-09-19 15:15:01 +00:00
{
dSprintf ( returnBuffer + returnLen , maxBufferSize - returnLen , " %s " , Namespace : : getActivePackage ( i ) ) ;
returnLen = dStrlen ( returnBuffer ) ;
}
// Trim off the last extra space
if ( returnLen > 0 & & returnBuffer [ returnLen - 1 ] = = ' ' )
returnBuffer [ returnLen - 1 ] = ' \0 ' ;
return returnBuffer ;
}