2009-05-08 13:28:41 +00:00
/*
* OpenClonk , http : //www.openclonk.org
*
2013-12-17 20:01:09 +00:00
* Copyright ( c ) 2001 - 2009 , RedWolf Design GmbH , http : //www.clonk.de/
2016-04-03 18:18:29 +00:00
* Copyright ( c ) 2009 - 2016 , The OpenClonk Team and contributors
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* Distributed under the terms of the ISC license ; see accompanying file
* " COPYING " for details .
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* " Clonk " is a registered trademark of Matthes Bender , used with permission .
* See accompanying file " TRADEMARK " for details .
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* To redistribute this file separately , substitute the full license texts
* for the above references .
2009-05-08 13:28:41 +00:00
*/
2009-10-20 03:39:24 +00:00
# include "C4Include.h"
2016-04-03 18:07:56 +00:00
# include "lib/StdCompiler.h"
2009-05-08 13:28:41 +00:00
// *** StdCompiler
void StdCompiler : : Warn ( const char * szWarning , . . . )
{
2010-03-27 16:05:02 +00:00
// Got warning callback?
2010-03-28 18:58:01 +00:00
if ( ! pWarnCB ) return ;
2010-03-27 16:05:02 +00:00
// Format message
va_list args ; va_start ( args , szWarning ) ;
StdStrBuf Msg ; Msg . FormatV ( szWarning , args ) ;
// do callback
( * pWarnCB ) ( pWarnData , getPosition ( ) . getData ( ) , Msg . getData ( ) ) ;
2009-05-08 13:28:41 +00:00
}
2010-04-01 21:08:06 +00:00
char StdCompiler : : SeparatorToChar ( Sep eSep )
2009-05-08 13:28:41 +00:00
{
2010-03-28 18:58:01 +00:00
switch ( eSep )
2009-05-08 13:28:41 +00:00
{
2010-03-27 16:05:02 +00:00
case SEP_SEP : return ' , ' ;
case SEP_SEP2 : return ' ; ' ;
case SEP_SET : return ' = ' ;
case SEP_PART : return ' . ' ;
case SEP_PART2 : return ' : ' ;
2009-05-08 13:28:41 +00:00
case SEP_PLUS : return ' + ' ;
case SEP_START : return ' ( ' ;
case SEP_END : return ' ) ' ;
case SEP_START2 : return ' [ ' ;
case SEP_END2 : return ' ] ' ;
case SEP_VLINE : return ' | ' ;
2010-03-27 16:05:02 +00:00
case SEP_DOLLAR : return ' $ ' ;
2010-04-01 21:08:06 +00:00
default : assert ( ! " Unhandled Separator value " ) ;
2009-05-08 13:28:41 +00:00
}
return ' ' ;
}
2017-03-27 00:55:27 +00:00
bool StdCompiler : : IsStringEnd ( char c , RawCompileType eType )
{
switch ( eType )
{
case RCT_Escaped : return c = = ' " ' | | ! c | | c = = ' \n ' | | c = = ' \r ' ;
case RCT_All : return ! c | | c = = ' \n ' | | c = = ' \r ' ;
// '-' is needed for Layers in Scenario.txt (C4NameList) and other Material-Texture combinations
case RCT_Idtf : case RCT_IdtfAllowEmpty : case RCT_ID : return ! isalnum ( ( unsigned char ) c ) & & c ! = ' _ ' & & c ! = ' - ' ;
}
// unreachable
return true ;
}
2009-05-08 13:28:41 +00:00
// *** StdCompilerBinWrite
void StdCompilerBinWrite : : DWord ( int32_t & rInt ) { WriteValue ( rInt ) ; }
void StdCompilerBinWrite : : DWord ( uint32_t & rInt ) { WriteValue ( rInt ) ; }
void StdCompilerBinWrite : : Word ( int16_t & rShort ) { WriteValue ( rShort ) ; }
void StdCompilerBinWrite : : Word ( uint16_t & rShort ) { WriteValue ( rShort ) ; }
void StdCompilerBinWrite : : Byte ( int8_t & rByte ) { WriteValue ( rByte ) ; }
void StdCompilerBinWrite : : Byte ( uint8_t & rByte ) { WriteValue ( rByte ) ; }
void StdCompilerBinWrite : : Boolean ( bool & rBool ) { WriteValue ( rBool ) ; }
void StdCompilerBinWrite : : Character ( char & rChar ) { WriteValue ( rChar ) ; }
void StdCompilerBinWrite : : String ( char * szString , size_t iMaxLength , RawCompileType eType )
{
2010-03-27 16:05:02 +00:00
WriteData ( szString , strlen ( szString ) + 1 ) ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerBinWrite : : String ( char * * pszString , RawCompileType eType )
{
2010-03-28 18:58:01 +00:00
if ( * pszString )
2010-03-27 16:05:02 +00:00
WriteData ( * pszString , strlen ( * pszString ) + 1 ) ;
else
WriteValue ( ' \0 ' ) ;
2009-05-08 13:28:41 +00:00
}
2017-03-13 16:34:41 +00:00
void StdCompilerBinWrite : : String ( std : : string & str , RawCompileType type )
{
WriteData ( str . c_str ( ) , str . size ( ) + 1 ) ;
}
2009-05-08 13:28:41 +00:00
template < class T >
2010-03-28 18:58:01 +00:00
void StdCompilerBinWrite : : WriteValue ( const T & rValue )
{
// Copy data
if ( fSecondPass )
* getMBufPtr < T > ( Buf , iPos ) = rValue ;
iPos + = sizeof ( rValue ) ;
}
2009-05-08 13:28:41 +00:00
void StdCompilerBinWrite : : WriteData ( const void * pData , size_t iSize )
{
// Copy data
2010-03-28 18:58:01 +00:00
if ( fSecondPass )
2009-05-08 13:28:41 +00:00
Buf . Write ( pData , iSize , iPos ) ;
2010-03-27 16:05:02 +00:00
iPos + = iSize ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerBinWrite : : Raw ( void * pData , size_t iSize , RawCompileType eType )
{
// Copy data
2010-03-28 18:58:01 +00:00
if ( fSecondPass )
2009-05-08 13:28:41 +00:00
Buf . Write ( pData , iSize , iPos ) ;
2010-03-27 16:05:02 +00:00
iPos + = iSize ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerBinWrite : : Begin ( )
{
2010-03-27 16:05:02 +00:00
fSecondPass = false ; iPos = 0 ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerBinWrite : : BeginSecond ( )
{
2010-03-27 16:05:02 +00:00
Buf . New ( iPos ) ;
fSecondPass = true ; iPos = 0 ;
2009-05-08 13:28:41 +00:00
}
// *** StdCompilerBinRead
void StdCompilerBinRead : : DWord ( int32_t & rInt ) { ReadValue ( rInt ) ; }
void StdCompilerBinRead : : DWord ( uint32_t & rInt ) { ReadValue ( rInt ) ; }
void StdCompilerBinRead : : Word ( int16_t & rShort ) { ReadValue ( rShort ) ; }
void StdCompilerBinRead : : Word ( uint16_t & rShort ) { ReadValue ( rShort ) ; }
void StdCompilerBinRead : : Byte ( int8_t & rByte ) { ReadValue ( rByte ) ; }
void StdCompilerBinRead : : Byte ( uint8_t & rByte ) { ReadValue ( rByte ) ; }
void StdCompilerBinRead : : Boolean ( bool & rBool ) { ReadValue ( rBool ) ; }
void StdCompilerBinRead : : Character ( char & rChar ) { ReadValue ( rChar ) ; }
void StdCompilerBinRead : : String ( char * szString , size_t iMaxLength , RawCompileType eType )
{
// At least one byte data needed
2010-03-28 18:58:01 +00:00
if ( iPos > = Buf . getSize ( ) )
2009-05-08 13:28:41 +00:00
{ excEOF ( ) ; return ; }
// Copy until no data left
char * pPos = szString ;
2010-03-28 18:58:01 +00:00
while ( ( * pPos + + = * getBufPtr < char > ( Buf , iPos + + ) ) )
if ( iPos > = Buf . getSize ( ) )
2009-05-08 13:28:41 +00:00
{ excEOF ( ) ; return ; }
2010-03-28 18:58:01 +00:00
else if ( pPos > szString + iMaxLength )
2009-05-08 13:28:41 +00:00
{ excCorrupt ( " string too long " ) ; return ; }
}
void StdCompilerBinRead : : String ( char * * pszString , RawCompileType eType )
{
// At least one byte data needed
2010-03-28 18:58:01 +00:00
if ( iPos > = Buf . getSize ( ) )
2009-05-08 13:28:41 +00:00
{ excEOF ( ) ; return ; }
int iStart = iPos ;
// Search string end
2010-03-28 18:58:01 +00:00
while ( * getBufPtr < char > ( Buf , iPos + + ) )
if ( iPos > = Buf . getSize ( ) )
2009-05-08 13:28:41 +00:00
{ excEOF ( ) ; return ; }
// Allocate and copy data
2016-04-17 19:07:53 +00:00
* pszString = ( char * ) malloc ( iPos - iStart ) ;
2009-05-08 13:28:41 +00:00
memcpy ( * pszString , Buf . getPtr ( iStart ) , iPos - iStart ) ;
}
2017-03-13 16:34:41 +00:00
void StdCompilerBinRead : : String ( std : : string & str , RawCompileType type )
{
// At least one byte data needed
if ( iPos > = Buf . getSize ( ) )
{
excEOF ( ) ; return ;
}
int iStart = iPos ;
// Search string end
while ( * getBufPtr < char > ( Buf , iPos + + ) )
if ( iPos > = Buf . getSize ( ) )
{
excEOF ( ) ; return ;
}
// Copy data
str . assign ( getBufPtr < char > ( Buf , iStart ) , getBufPtr < char > ( Buf , iPos ) ) ;
}
2009-05-08 13:28:41 +00:00
void StdCompilerBinRead : : Raw ( void * pData , size_t iSize , RawCompileType eType )
{
2010-03-28 18:58:01 +00:00
if ( iPos + iSize > Buf . getSize ( ) )
2009-05-08 13:28:41 +00:00
{ excEOF ( ) ; return ; }
2010-03-27 16:05:02 +00:00
// Copy data
memcpy ( pData , Buf . getPtr ( iPos ) , iSize ) ;
iPos + = iSize ;
2009-05-08 13:28:41 +00:00
}
StdStrBuf StdCompilerBinRead : : getPosition ( ) const
{
return FormatString ( " byte %ld " , static_cast < unsigned long > ( iPos ) ) ;
}
template < class T >
2010-03-28 18:58:01 +00:00
inline void StdCompilerBinRead : : ReadValue ( T & rValue )
{
2017-05-07 11:50:00 +00:00
// Pufferüberhang prüfen
2010-03-28 18:58:01 +00:00
if ( iPos + sizeof ( T ) > Buf . getSize ( ) )
{ excEOF ( ) ; return ; }
// Kopieren
rValue = * getBufPtr < T > ( Buf , iPos ) ;
iPos + = sizeof ( T ) ;
}
2009-05-08 13:28:41 +00:00
void StdCompilerBinRead : : Begin ( )
{
iPos = 0 ;
}
// *** StdCompilerINIWrite
bool StdCompilerINIWrite : : Name ( const char * szName )
{
2010-03-27 16:05:02 +00:00
// Sub-Namesections exist, so it's a section. Write name if not already done so.
2010-03-28 18:58:01 +00:00
if ( fPutName ) PutName ( true ) ;
2010-03-27 16:05:02 +00:00
// Push struct
Naming * pnNaming = new Naming ;
pnNaming - > Name . Copy ( szName ) ;
pnNaming - > Parent = pNaming ;
pNaming = pnNaming ;
iDepth + + ;
// Done
fPutName = true ; fInSection = false ;
return true ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerINIWrite : : NameEnd ( bool fBreak )
{
2010-03-27 16:05:02 +00:00
// Append newline
2010-03-28 18:58:01 +00:00
if ( ! fPutName & & ! fInSection )
2019-02-19 14:28:12 +00:00
Buf . Append ( " \n " ) ;
2009-05-08 13:28:41 +00:00
fPutName = false ;
// Note this makes it impossible to distinguish an empty name section from
// a non-existing name section.
2010-03-27 16:05:02 +00:00
// Pop
assert ( iDepth ) ;
Naming * poNaming = pNaming ;
pNaming = poNaming - > Parent ;
delete poNaming ;
iDepth - - ;
// We're inside a section now
fInSection = true ;
2009-05-08 13:28:41 +00:00
}
2010-04-01 21:08:06 +00:00
bool StdCompilerINIWrite : : Separator ( Sep eSep )
2009-05-08 13:28:41 +00:00
{
2010-03-28 18:58:01 +00:00
if ( fInSection )
2010-03-27 16:05:02 +00:00
{
// Re-put section name
PutName ( true ) ;
}
else
2009-05-08 13:28:41 +00:00
{
PrepareForValue ( ) ;
2010-04-01 21:08:06 +00:00
Buf . AppendChar ( SeparatorToChar ( eSep ) ) ;
2009-05-08 13:28:41 +00:00
}
2010-03-27 16:05:02 +00:00
return true ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerINIWrite : : DWord ( int32_t & rInt )
{
2010-03-27 16:05:02 +00:00
PrepareForValue ( ) ;
Buf . AppendFormat ( " %d " , rInt ) ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerINIWrite : : DWord ( uint32_t & rInt )
{
2010-03-27 16:05:02 +00:00
PrepareForValue ( ) ;
Buf . AppendFormat ( " %u " , rInt ) ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerINIWrite : : Word ( int16_t & rInt )
{
2010-03-27 16:05:02 +00:00
PrepareForValue ( ) ;
Buf . AppendFormat ( " %d " , rInt ) ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerINIWrite : : Word ( uint16_t & rInt )
{
2010-03-27 16:05:02 +00:00
PrepareForValue ( ) ;
Buf . AppendFormat ( " %u " , rInt ) ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerINIWrite : : Byte ( int8_t & rByte )
{
2010-03-27 16:05:02 +00:00
PrepareForValue ( ) ;
Buf . AppendFormat ( " %d " , rByte ) ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerINIWrite : : Byte ( uint8_t & rInt )
{
2010-03-27 16:05:02 +00:00
PrepareForValue ( ) ;
Buf . AppendFormat ( " %u " , rInt ) ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerINIWrite : : Boolean ( bool & rBool )
{
2010-03-27 16:05:02 +00:00
PrepareForValue ( ) ;
Buf . Append ( rBool ? " true " : " false " ) ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerINIWrite : : Character ( char & rChar )
{
2010-03-27 16:05:02 +00:00
PrepareForValue ( ) ;
Buf . AppendFormat ( " %c " , rChar ) ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerINIWrite : : String ( char * szString , size_t iMaxLength , RawCompileType eType )
2017-08-15 03:50:38 +00:00
{
2017-08-24 14:40:05 +00:00
StringN ( szString , strnlen ( szString , iMaxLength ) , eType ) ;
2017-08-15 03:50:38 +00:00
}
2017-08-24 14:40:05 +00:00
void StdCompilerINIWrite : : StringN ( const char * szString , size_t iLength , RawCompileType eType )
2009-05-08 13:28:41 +00:00
{
2010-03-27 16:05:02 +00:00
PrepareForValue ( ) ;
2010-03-28 18:58:01 +00:00
switch ( eType )
2010-03-27 16:05:02 +00:00
{
case RCT_Escaped :
2017-08-24 14:40:05 +00:00
WriteEscaped ( szString , szString + iLength ) ;
2010-03-27 16:05:02 +00:00
break ;
case RCT_All :
case RCT_Idtf :
2009-05-08 13:28:41 +00:00
case RCT_IdtfAllowEmpty :
2010-03-27 16:05:02 +00:00
case RCT_ID :
Buf . Append ( szString ) ;
}
2009-05-08 13:28:41 +00:00
}
void StdCompilerINIWrite : : String ( char * * pszString , RawCompileType eType )
{
2017-08-15 03:50:38 +00:00
assert ( pszString ) ;
2010-03-27 16:05:02 +00:00
char cNull = ' \0 ' ;
2017-08-25 13:10:28 +00:00
char * szString = * pszString ? * pszString : & cNull ;
String ( szString , strlen ( szString ) , eType ) ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerINIWrite : : Raw ( void * pData , size_t iSize , RawCompileType eType )
{
2010-03-28 18:58:01 +00:00
switch ( eType )
2010-03-27 16:05:02 +00:00
{
case RCT_Escaped :
WriteEscaped ( reinterpret_cast < char * > ( pData ) , reinterpret_cast < char * > ( pData ) + iSize ) ;
break ;
case RCT_All :
case RCT_Idtf :
2009-05-08 13:28:41 +00:00
case RCT_IdtfAllowEmpty :
2010-03-27 16:05:02 +00:00
case RCT_ID :
Buf . Append ( reinterpret_cast < char * > ( pData ) , iSize ) ;
}
2009-05-08 13:28:41 +00:00
}
2017-03-13 16:34:41 +00:00
void StdCompilerINIWrite : : String ( std : : string & str , RawCompileType type )
{
2017-08-24 14:40:05 +00:00
StringN ( str . c_str ( ) , str . size ( ) , type ) ;
2017-03-13 16:34:41 +00:00
}
2009-05-08 13:28:41 +00:00
void StdCompilerINIWrite : : Begin ( )
{
2016-11-02 23:58:02 +00:00
pNaming = nullptr ;
2010-03-27 16:05:02 +00:00
fPutName = false ;
iDepth = 0 ;
fInSection = false ;
Buf . Clear ( ) ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerINIWrite : : End ( )
{
2010-03-27 16:05:02 +00:00
// Ensure all namings were closed properly
assert ( ! iDepth ) ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerINIWrite : : PrepareForValue ( )
{
2010-03-27 16:05:02 +00:00
// Put name (value-type), if not already done so
2010-03-28 18:58:01 +00:00
if ( fPutName ) PutName ( false ) ;
2010-03-27 16:05:02 +00:00
// No data allowed inside of sections
assert ( ! fInSection ) ;
// No values allowed on top-level - must be contained in at least one section
assert ( iDepth > 1 ) ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerINIWrite : : WriteEscaped ( const char * szString , const char * pEnd )
{
2010-03-27 16:05:02 +00:00
Buf . AppendChar ( ' " ' ) ;
// Try to write chunks as huge as possible of "normal" chars.
// Note this excludes '\0', so the standard Append() can be used.
const char * pStart , * pPos ; pStart = pPos = szString ;
bool fLastNumEscape = false ; // catch "\1""1", which must become "\1\61"
2010-03-28 18:58:01 +00:00
for ( ; pPos < pEnd ; pPos + + )
if ( ! isprint ( ( unsigned char ) ( unsigned char ) * pPos ) | | * pPos = = ' \\ ' | | * pPos = = ' " ' | | ( fLastNumEscape & & isdigit ( ( unsigned char ) * pPos ) ) )
2010-03-27 16:05:02 +00:00
{
// Write everything up to this point
2010-03-28 18:58:01 +00:00
if ( pPos - pStart ) Buf . Append ( pStart , pPos - pStart ) ;
2010-03-27 16:05:02 +00:00
// Escape
fLastNumEscape = false ;
2010-03-28 18:58:01 +00:00
switch ( * pPos )
2010-03-27 16:05:02 +00:00
{
2017-05-03 18:28:00 +00:00
case ' \a ' : Buf . Append ( R " ( \a ) " ) ; break ;
case ' \b ' : Buf . Append ( R " ( \b ) " ) ; break ;
case ' \f ' : Buf . Append ( R " ( \f ) " ) ; break ;
case ' \n ' : Buf . Append ( R " ( \n ) " ) ; break ;
case ' \r ' : Buf . Append ( R " ( \r ) " ) ; break ;
case ' \t ' : Buf . Append ( R " ( \t ) " ) ; break ;
case ' \v ' : Buf . Append ( R " ( \v ) " ) ; break ;
case ' \" ' : Buf . Append ( R " ( \" ) " ) ; break ;
case ' \\ ' : Buf . Append ( R " ( \\ ) " ) ; break ;
2010-03-27 16:05:02 +00:00
default :
2017-05-03 18:28:00 +00:00
Buf . AppendFormat ( R " ( \ %o) " , * reinterpret_cast < const unsigned char * > ( pPos ) ) ;
2010-03-27 16:05:02 +00:00
fLastNumEscape = true ;
}
// Set pointer
pStart = pPos + 1 ;
}
else
fLastNumEscape = false ;
// Write the rest
2010-03-28 18:58:01 +00:00
if ( pEnd - pStart ) Buf . Append ( pStart , pEnd - pStart ) ;
2010-03-27 16:05:02 +00:00
Buf . AppendChar ( ' " ' ) ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerINIWrite : : WriteIndent ( bool fSection )
{
2010-03-27 16:05:02 +00:00
// Do not indent level 1 (level 0 values aren't allowed - see above)
int iIndent = iDepth - 1 ;
// Sections are indented more, even though they belong to this level
2010-03-28 18:58:01 +00:00
if ( ! fSection ) iIndent - - ;
2010-03-27 16:05:02 +00:00
// Do indention
2010-03-28 18:58:01 +00:00
if ( iIndent < = 0 ) return ;
2010-03-27 16:05:02 +00:00
Buf . AppendChars ( ' ' , iIndent * 2 ) ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerINIWrite : : PutName ( bool fSection )
{
2010-03-28 18:58:01 +00:00
if ( fSection & & Buf . getLength ( ) )
2019-02-19 14:28:12 +00:00
Buf . Append ( " \n " ) ;
2010-03-27 16:05:02 +00:00
WriteIndent ( fSection ) ;
// Put name
2010-03-28 18:58:01 +00:00
if ( fSection )
2019-02-19 14:28:12 +00:00
Buf . AppendFormat ( " [%s] \n " , pNaming - > Name . getData ( ) ) ;
2010-03-27 16:05:02 +00:00
else
Buf . AppendFormat ( " %s= " , pNaming - > Name . getData ( ) ) ;
// Set flag
fPutName = false ;
2009-05-08 13:28:41 +00:00
}
// *** StdCompilerINIRead
2017-05-07 11:50:00 +00:00
StdCompilerINIRead : : StdCompilerINIRead ( ) = default ;
2009-05-08 13:28:41 +00:00
StdCompilerINIRead : : ~ StdCompilerINIRead ( )
{
2010-03-27 16:05:02 +00:00
FreeNameTree ( ) ;
2009-05-08 13:28:41 +00:00
}
// Naming
bool StdCompilerINIRead : : Name ( const char * szName )
{
2010-03-27 16:05:02 +00:00
// Increase depth
iDepth + + ;
// Parent category virtual?
2010-03-28 18:58:01 +00:00
if ( iDepth - 1 > iRealDepth )
2010-03-27 16:05:02 +00:00
return false ;
// Name must be alphanumerical and non-empty (force it)
2010-03-28 18:58:01 +00:00
if ( ! isalpha ( ( unsigned char ) * szName ) )
2010-03-27 16:05:02 +00:00
{ assert ( false ) ; return false ; }
2010-03-28 18:58:01 +00:00
for ( const char * p = szName + 1 ; * p ; p + + )
2010-03-27 16:05:02 +00:00
// C4Update needs Name**...
2010-03-28 18:58:01 +00:00
if ( ! isalnum ( ( unsigned char ) * p ) & & * p ! = ' ' & & * p ! = ' _ ' & & * p ! = ' * ' )
2010-03-27 16:05:02 +00:00
{ assert ( false ) ; return false ; }
// Search name
NameNode * pNode ;
2010-03-28 18:58:01 +00:00
for ( pNode = pName - > FirstChild ; pNode ; pNode = pNode - > NextChild )
if ( pNode - > Pos & & pNode - > Name = = szName )
2010-03-27 16:05:02 +00:00
break ;
// Not found?
2010-03-28 18:58:01 +00:00
if ( ! pNode )
2009-05-08 13:28:41 +00:00
{
NotFoundName = szName ;
return false ;
}
2010-03-27 16:05:02 +00:00
// Save tree position, indicate success
pName = pNode ;
pPos = pName - > Pos ;
2016-11-02 23:58:02 +00:00
pReenter = nullptr ;
2010-03-27 16:05:02 +00:00
iRealDepth + + ;
return true ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerINIRead : : NameEnd ( bool fBreak )
{
2010-03-27 16:05:02 +00:00
assert ( iDepth > 0 ) ;
2010-03-28 18:58:01 +00:00
if ( iRealDepth = = iDepth )
2010-03-27 16:05:02 +00:00
{
2009-05-08 13:28:41 +00:00
// Remove childs
2010-03-28 18:58:01 +00:00
for ( NameNode * pNode = pName - > FirstChild , * pNext ; pNode ; pNode = pNext )
2009-05-08 13:28:41 +00:00
{
// Report unused entries
2010-03-28 18:58:01 +00:00
if ( pNode - > Pos & & ! fBreak )
2017-05-03 18:28:00 +00:00
Warn ( R " (Unexpected %s " % s " !) " , pNode - > Section ? " section " : " value " , pNode - > Name . getData ( ) ) ;
2009-05-08 13:28:41 +00:00
// delete node
pNext = pNode - > NextChild ;
delete pNode ;
}
2010-03-27 16:05:02 +00:00
// Remove name so it won't be found again
2009-05-08 13:28:41 +00:00
NameNode * pParent = pName - > Parent ;
( pName - > PrevChild ? pName - > PrevChild - > NextChild : pParent - > FirstChild ) = pName - > NextChild ;
( pName - > NextChild ? pName - > NextChild - > PrevChild : pParent - > LastChild ) = pName - > PrevChild ;
delete pName ;
2010-03-27 16:05:02 +00:00
// Go up
pName = pParent ;
iRealDepth - - ;
}
// Decrease depth
iDepth - - ;
// This is the middle of nowhere
2016-11-02 23:58:02 +00:00
pPos = nullptr ; pReenter = nullptr ;
2009-05-08 13:28:41 +00:00
}
bool StdCompilerINIRead : : FollowName ( const char * szName )
{
// Current naming virtual?
2010-03-28 18:58:01 +00:00
if ( iDepth > iRealDepth )
2010-03-27 16:05:02 +00:00
return false ;
2009-05-08 13:28:41 +00:00
// Next section must be the one
2010-03-28 18:58:01 +00:00
if ( ! pName - > NextChild | | pName - > NextChild - > Name ! = szName )
2009-05-08 13:28:41 +00:00
{
// End current naming
NameEnd ( ) ;
// Go into virtual naming
iDepth + + ;
return false ;
}
// End current naming
NameEnd ( ) ;
// Start new one
Name ( szName ) ;
// Done
return true ;
}
2010-04-01 21:08:06 +00:00
// Separators
bool StdCompilerINIRead : : Separator ( Sep eSep )
2009-05-08 13:28:41 +00:00
{
2010-03-28 18:58:01 +00:00
if ( iDepth > iRealDepth ) return false ;
2010-03-27 16:05:02 +00:00
// In section?
2010-03-28 18:58:01 +00:00
if ( pName - > Section )
2010-03-27 16:05:02 +00:00
{
// Store current name, search another section with the same name
StdStrBuf CurrName = pName - > Name ;
NameEnd ( ) ;
return Name ( CurrName . getData ( ) ) ;
}
2010-04-01 21:08:06 +00:00
// Position saved back from separator mismatch?
2016-11-02 23:58:02 +00:00
if ( pReenter ) { pPos = pReenter ; pReenter = nullptr ; }
2009-05-08 13:28:41 +00:00
// Nothing to read?
2010-03-28 18:58:01 +00:00
if ( ! pPos ) return false ;
2010-03-27 16:05:02 +00:00
// Read (while skipping over whitespace)
SkipWhitespace ( ) ;
2010-04-01 21:08:06 +00:00
// Separator mismatch? Let all read attempts fail until the correct separator is found or the naming ends.
2016-11-02 23:58:02 +00:00
if ( * pPos ! = SeparatorToChar ( eSep ) ) { pReenter = pPos ; pPos = nullptr ; return false ; }
2010-04-01 21:08:06 +00:00
// Go over separator, success
2010-03-27 16:05:02 +00:00
pPos + + ;
return true ;
2009-05-08 13:28:41 +00:00
}
2010-04-01 21:08:06 +00:00
void StdCompilerINIRead : : NoSeparator ( )
2009-05-08 13:28:41 +00:00
{
2010-04-01 21:08:06 +00:00
// Position saved back from separator mismatch?
2016-11-02 23:58:02 +00:00
if ( pReenter ) { pPos = pReenter ; pReenter = nullptr ; }
2009-05-08 13:28:41 +00:00
}
int StdCompilerINIRead : : NameCount ( const char * szName )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// not in virtual naming
if ( iDepth > iRealDepth | | ! pName ) return 0 ;
// count within current name
int iCount = 0 ;
2010-03-27 16:05:02 +00:00
NameNode * pNode ;
2010-03-28 18:58:01 +00:00
for ( pNode = pName - > FirstChild ; pNode ; pNode = pNode - > NextChild )
2009-05-08 13:28:41 +00:00
// if no name is given, all valid subsections are counted
2010-03-28 18:58:01 +00:00
if ( pNode - > Pos & & ( ! szName | | pNode - > Name = = szName ) )
2010-03-27 16:05:02 +00:00
+ + iCount ;
2009-05-08 13:28:41 +00:00
return iCount ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2017-08-15 03:50:38 +00:00
const char * StdCompilerINIRead : : GetNameByIndex ( size_t idx ) const
2014-09-23 21:02:03 +00:00
{
// not in virtual naming
2017-05-03 18:28:00 +00:00
if ( iDepth > iRealDepth | | ! pName ) return nullptr ;
2014-09-23 21:02:03 +00:00
// count within current name
NameNode * pNode ;
for ( pNode = pName - > FirstChild ; pNode ; pNode = pNode - > NextChild )
// all valid subsections are counted
if ( pNode - > Pos )
if ( ! idx - - )
return pNode - > Name . getData ( ) ;
// index out of range
2016-11-02 23:58:02 +00:00
return nullptr ;
2014-09-23 21:02:03 +00:00
}
2009-05-08 13:28:41 +00:00
// Various data readers
void StdCompilerINIRead : : DWord ( int32_t & rInt )
{
2010-03-27 16:05:02 +00:00
rInt = ReadNum ( ) ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerINIRead : : DWord ( uint32_t & rInt )
{
2010-03-27 16:05:02 +00:00
rInt = ReadUNum ( ) ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerINIRead : : Word ( int16_t & rShort )
{
2010-03-27 16:05:02 +00:00
const int MIN = - ( 1 < < 15 ) , MAX = ( 1 < < 15 ) - 1 ;
int iNum = ReadNum ( ) ;
2010-03-28 18:58:01 +00:00
if ( iNum < MIN | | iNum > MAX )
2010-03-27 16:05:02 +00:00
Warn ( " number out of range (%d to %d): %d " , MIN , MAX , iNum ) ;
2015-02-12 22:05:55 +00:00
rShort = Clamp ( iNum , MIN , MAX ) ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerINIRead : : Word ( uint16_t & rShort )
{
2016-01-02 22:38:06 +00:00
const unsigned int MIN = 0 , MAX = ( 1 < < 16 ) - 1 ;
2010-03-27 16:05:02 +00:00
unsigned int iNum = ReadUNum ( ) ;
2010-03-28 18:58:01 +00:00
if ( iNum > MAX )
2010-03-27 16:05:02 +00:00
Warn ( " number out of range (%u to %u): %u " , MIN , MAX , iNum ) ;
2015-02-12 22:05:55 +00:00
rShort = Clamp ( iNum , MIN , MAX ) ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerINIRead : : Byte ( int8_t & rByte )
{
2010-03-27 16:05:02 +00:00
const int MIN = - ( 1 < < 7 ) , MAX = ( 1 < < 7 ) - 1 ;
int iNum = ReadNum ( ) ;
2010-03-28 18:58:01 +00:00
if ( iNum < MIN | | iNum > MAX )
2010-03-27 16:05:02 +00:00
Warn ( " number out of range (%d to %d): %d " , MIN , MAX , iNum ) ;
2015-02-12 22:05:55 +00:00
rByte = Clamp ( iNum , MIN , MAX ) ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerINIRead : : Byte ( uint8_t & rByte )
{
2010-03-27 16:05:02 +00:00
const unsigned int MIN = 0 , MAX = ( 1 < < 8 ) - 1 ;
unsigned int iNum = ReadUNum ( ) ;
2010-03-28 18:58:01 +00:00
if ( iNum > MAX )
2010-03-27 16:05:02 +00:00
Warn ( " number out of range (%u to %u): %u " , MIN , MAX , iNum ) ;
2015-02-12 22:05:55 +00:00
rByte = Clamp ( iNum , MIN , MAX ) ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerINIRead : : Boolean ( bool & rBool )
{
2010-03-28 18:58:01 +00:00
if ( ! pPos ) { notFound ( " Boolean " ) ; return ; }
if ( * pPos = = ' 1 ' & & ! isdigit ( ( unsigned char ) * ( pPos + 1 ) ) )
2010-03-27 16:05:02 +00:00
{ rBool = true ; pPos + + ; }
2010-03-28 18:58:01 +00:00
else if ( * pPos = = ' 0 ' & & ! isdigit ( ( unsigned char ) * ( pPos + 1 ) ) )
2010-03-27 16:05:02 +00:00
{ rBool = false ; pPos + + ; }
2010-03-28 18:58:01 +00:00
else if ( SEqual2 ( pPos , " true " ) )
2010-03-27 16:05:02 +00:00
{ rBool = true ; pPos + = 4 ; }
2010-03-28 18:58:01 +00:00
else if ( SEqual2 ( pPos , " false " ) )
2010-03-27 16:05:02 +00:00
{ rBool = false ; pPos + = 5 ; }
else
2009-05-08 13:28:41 +00:00
{ notFound ( " Boolean " ) ; return ; }
}
void StdCompilerINIRead : : Character ( char & rChar )
{
2010-03-28 18:58:01 +00:00
if ( ! pPos | | ! isalpha ( ( unsigned char ) * pPos ) )
2009-05-08 13:28:41 +00:00
{ notFound ( " Character " ) ; return ; }
2010-03-27 16:05:02 +00:00
rChar = * pPos + + ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerINIRead : : String ( char * szString , size_t iMaxLength , RawCompileType eType )
{
2010-03-27 16:05:02 +00:00
// Read data
StdBuf Buf = ReadString ( iMaxLength , eType , true ) ;
// Copy
SCopy ( getBufPtr < char > ( Buf ) , szString , iMaxLength ) ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerINIRead : : String ( char * * pszString , RawCompileType eType )
{
2010-03-27 16:05:02 +00:00
// Get length
size_t iLength = GetStringLength ( eType ) ;
// Read data
StdBuf Buf = ReadString ( iLength , eType , true ) ;
// Set
* pszString = reinterpret_cast < char * > ( Buf . GrabPointer ( ) ) ;
2009-05-08 13:28:41 +00:00
}
2017-03-13 16:34:41 +00:00
void StdCompilerINIRead : : String ( std : : string & str , RawCompileType type )
{
// Get length
size_t iLength = GetStringLength ( type ) ;
// Read data
StdBuf Buf = ReadString ( iLength , type , true ) ;
str = getBufPtr < char > ( Buf ) ;
}
2009-05-08 13:28:41 +00:00
void StdCompilerINIRead : : Raw ( void * pData , size_t iSize , RawCompileType eType )
{
2010-03-27 16:05:02 +00:00
// Read data
StdBuf Buf = ReadString ( iSize , eType , false ) ;
// Correct size?
2010-03-28 18:58:01 +00:00
if ( Buf . getSize ( ) ! = iSize )
2010-03-27 16:05:02 +00:00
Warn ( " got %u bytes raw data, but %u bytes expected! " , Buf . getSize ( ) , iSize ) ;
// Copy
MemCopy ( Buf . getData ( ) , pData , iSize ) ;
2009-05-08 13:28:41 +00:00
}
2015-05-10 18:09:51 +00:00
uint32_t StdCompilerINIRead : : getLineNumberOfPos ( const char * pos ) const
{
// Figure out quickly whether we already know which line this is
auto entry = std : : lower_bound ( lineBreaks . begin ( ) , lineBreaks . end ( ) , pos ) ;
if ( entry ! = lineBreaks . end ( ) )
{
return std : : distance ( lineBreaks . begin ( ) , entry ) + 1 ;
}
// Otherwise search through the buffer until we find out, filling the
// cache in the process
const char * cursor = Buf . getData ( ) ;
if ( ! lineBreaks . empty ( ) )
cursor = * ( lineBreaks . end ( ) - 1 ) + 1 ;
for ( ; ; )
{
if ( * cursor = = ' \0 ' | | * cursor = = ' \n ' )
{
lineBreaks . push_back ( cursor ) ;
// If we're at the end of the file or have found the line break
// past the requested position, we're done for now
if ( * cursor = = ' \0 ' | | pos < cursor )
{
break ;
}
}
+ + cursor ;
}
return std : : distance ( lineBreaks . begin ( ) ,
std : : lower_bound ( lineBreaks . begin ( ) , lineBreaks . end ( ) , pos ) ) + 1 ;
}
2010-03-28 18:58:01 +00:00
StdStrBuf StdCompilerINIRead : : getPosition ( ) const
2009-05-08 13:28:41 +00:00
{
2010-03-28 18:58:01 +00:00
if ( pPos )
2015-05-10 18:09:51 +00:00
return FormatString ( " line %d " , getLineNumberOfPos ( pPos ) ) ;
2010-03-28 18:58:01 +00:00
else if ( iDepth = = iRealDepth )
2017-05-03 18:28:00 +00:00
return FormatString ( pName - > Section ? R " (section " % s " , after line %d) " : R " ( value " %s " , line % d ) " , pName->Name.getData(), getLineNumberOfPos(pName->Pos)) ;
2010-03-28 18:58:01 +00:00
else if ( iRealDepth )
2017-05-03 18:28:00 +00:00
return FormatString ( R " (missing value/section " % s " inside section " % s " (line %d) ) " , NotFoundName.getData(), pName->Name.getData(), getLineNumberOfPos(pName->Pos)) ;
2009-05-08 13:28:41 +00:00
else
2017-05-03 18:28:00 +00:00
return FormatString ( R " (missing value/section " % s " ) " , NotFoundName.getData()) ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerINIRead : : Begin ( )
{
2010-03-27 16:05:02 +00:00
// Already running? This may happen if someone confuses Compile with Value.
assert ( ! iDepth & & ! iRealDepth & & ! pNameRoot ) ;
// Create tree
CreateNameTree ( ) ;
// Start must be inside a section
iDepth = iRealDepth = 0 ;
2016-11-02 23:58:02 +00:00
pPos = nullptr ; pReenter = nullptr ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerINIRead : : End ( )
{
2010-03-27 16:05:02 +00:00
assert ( ! iDepth & & ! iRealDepth ) ;
FreeNameTree ( ) ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerINIRead : : CreateNameTree ( )
{
FreeNameTree ( ) ;
2010-03-27 16:05:02 +00:00
// Create root node
pName = pNameRoot = new NameNode ( ) ;
2009-05-08 13:28:41 +00:00
// No input? Stop
2010-03-28 18:58:01 +00:00
if ( ! Buf ) return ;
2010-03-27 16:05:02 +00:00
// Start scanning
pPos = Buf . getPtr ( 0 ) ;
2010-03-28 18:58:01 +00:00
while ( * pPos )
2010-03-27 16:05:02 +00:00
{
// Go over whitespace
int iIndent = 0 ;
2010-03-28 18:58:01 +00:00
while ( * pPos = = ' ' | | * pPos = = ' \t ' )
2010-03-27 16:05:02 +00:00
{ pPos + + ; iIndent + + ; }
// Name/Section?
bool fSection = * pPos = = ' [ ' & & isalpha ( ( unsigned char ) * ( pPos + 1 ) ) ;
2010-03-28 18:58:01 +00:00
if ( fSection | | isalpha ( ( unsigned char ) * pPos ) )
2010-03-27 16:05:02 +00:00
{
// Treat values as if they had more indention
// (so they become children of sections on the same level)
2010-03-28 18:58:01 +00:00
if ( ! fSection ) iIndent + + ; else pPos + + ;
2010-03-27 16:05:02 +00:00
// Go up in tree structure if there is less indention
2010-03-28 18:58:01 +00:00
while ( pName - > Parent & & pName - > Indent > = iIndent )
2010-03-27 16:05:02 +00:00
pName = pName - > Parent ;
// Copy name
StdStrBuf Name ;
2010-03-28 18:58:01 +00:00
while ( isalnum ( ( unsigned char ) * pPos ) | | * pPos = = ' ' | | * pPos = = ' _ ' )
2010-03-27 16:05:02 +00:00
Name . AppendChar ( * pPos + + ) ;
2010-03-28 18:58:01 +00:00
while ( * pPos = = ' ' | | * pPos = = ' \t ' ) pPos + + ;
if ( * pPos ! = ( fSection ? ' ] ' : ' = ' ) )
2010-03-27 16:05:02 +00:00
// Warn, ignore
Warn ( isprint ( ( unsigned char ) * pPos ) ? " Unexpected character ('%c'): %s ignored " : " Unexpected character ('0x%02x'): %s ignored " , unsigned ( * pPos ) , fSection ? " section " : " value " ) ;
else
{
pPos + + ;
// Create new node
2009-05-08 13:28:41 +00:00
NameNode * pPrev = pName - > LastChild ;
2010-03-27 16:05:02 +00:00
pName =
2010-03-28 18:58:01 +00:00
pName - > LastChild =
( pName - > LastChild ? pName - > LastChild - > NextChild : pName - > FirstChild ) =
new NameNode ( pName ) ;
2009-05-08 13:28:41 +00:00
pName - > PrevChild = pPrev ;
2009-11-25 18:38:54 +00:00
pName - > Name . Take ( std : : move ( Name ) ) ;
2010-03-27 16:05:02 +00:00
pName - > Pos = pPos ;
pName - > Indent = iIndent ;
pName - > Section = fSection ;
// Values don't have children (even if the indention looks like it)
2010-03-28 18:58:01 +00:00
if ( ! fSection )
2010-03-27 16:05:02 +00:00
pName = pName - > Parent ;
}
}
// Skip line
2010-03-28 18:58:01 +00:00
while ( * pPos & & ( * pPos ! = ' \n ' & & * pPos ! = ' \r ' ) )
2010-03-27 16:05:02 +00:00
pPos + + ;
2010-03-28 18:58:01 +00:00
while ( * pPos = = ' \n ' | | * pPos = = ' \r ' )
2010-03-27 16:05:02 +00:00
pPos + + ;
}
// Set pointer back
pName = pNameRoot ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerINIRead : : FreeNameTree ( )
{
2010-03-27 16:05:02 +00:00
// free all nodes
2009-05-08 13:28:41 +00:00
FreeNameNode ( pNameRoot ) ;
2016-11-02 23:58:02 +00:00
pName = pNameRoot = nullptr ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerINIRead : : FreeNameNode ( NameNode * pDelNode )
{
NameNode * pNode = pDelNode ;
2010-03-28 18:58:01 +00:00
while ( pNode )
2010-03-27 16:05:02 +00:00
{
2010-03-28 18:58:01 +00:00
if ( pNode - > FirstChild )
2010-03-27 16:05:02 +00:00
pNode = pNode - > FirstChild ;
else
{
NameNode * pDelete = pNode ;
2009-05-08 13:28:41 +00:00
if ( pDelete = = pDelNode ) { delete pDelete ; break ; }
2010-03-28 18:58:01 +00:00
if ( pNode - > NextChild )
2009-05-08 13:28:41 +00:00
pNode = pNode - > NextChild ;
else
{
pNode = pNode - > Parent ;
2016-11-02 23:58:02 +00:00
if ( pNode ) pNode - > FirstChild = nullptr ;
2009-05-08 13:28:41 +00:00
}
2010-03-27 16:05:02 +00:00
delete pDelete ;
}
}
2009-05-08 13:28:41 +00:00
}
void StdCompilerINIRead : : SkipWhitespace ( )
{
2010-03-28 18:58:01 +00:00
while ( * pPos = = ' ' | | * pPos = = ' \t ' )
2010-03-27 16:05:02 +00:00
pPos + + ;
2009-05-08 13:28:41 +00:00
}
void StdCompilerINIRead : : SkipNum ( )
{
2010-03-28 18:58:01 +00:00
while ( * pPos = = ' + ' | | * pPos = = ' - ' | | isdigit ( ( unsigned char ) * pPos ) )
2010-03-27 16:05:02 +00:00
pPos + + ;
2009-05-08 13:28:41 +00:00
}
long StdCompilerINIRead : : ReadNum ( )
{
2010-03-28 18:58:01 +00:00
if ( ! pPos )
2009-05-08 13:28:41 +00:00
{ notFound ( " Number " ) ; return 0 ; }
2010-03-27 16:05:02 +00:00
// Skip whitespace
SkipWhitespace ( ) ;
2017-05-07 11:50:00 +00:00
// Read number. If this breaks, Günther is to blame!
2009-05-08 13:28:41 +00:00
const char * pnPos = pPos ;
long iNum = strtol ( pPos , const_cast < char * * > ( & pnPos ) , 10 ) ;
// Could not read?
2010-03-28 18:58:01 +00:00
if ( ! iNum & & pnPos = = pPos )
2009-05-08 13:28:41 +00:00
{ notFound ( " Number " ) ; return 0 ; }
2010-03-27 16:05:02 +00:00
// Get over it
pPos = pnPos ;
return iNum ;
2009-05-08 13:28:41 +00:00
}
unsigned long StdCompilerINIRead : : ReadUNum ( )
{
2010-03-28 18:58:01 +00:00
if ( ! pPos )
2009-05-08 13:28:41 +00:00
{ notFound ( " Number " ) ; return 0 ; }
2010-03-27 16:05:02 +00:00
// Skip whitespace
SkipWhitespace ( ) ;
2017-05-07 11:50:00 +00:00
// Read number. If this breaks, Günther is to blame!
2009-05-08 13:28:41 +00:00
const char * pnPos = pPos ;
unsigned long iNum = strtoul ( pPos , const_cast < char * * > ( & pnPos ) , 10 ) ;
// Could not read?
2010-03-28 18:58:01 +00:00
if ( ! iNum & & pnPos = = pPos )
2009-05-08 13:28:41 +00:00
{ notFound ( " Number " ) ; return 0 ; }
2010-03-27 16:05:02 +00:00
// Get over it
pPos = pnPos ;
return iNum ;
2009-05-08 13:28:41 +00:00
}
size_t StdCompilerINIRead : : GetStringLength ( RawCompileType eRawType )
{
2010-03-27 16:05:02 +00:00
// Excpect valid position
2010-03-28 18:58:01 +00:00
if ( ! pPos )
2009-05-08 13:28:41 +00:00
{ notFound ( " String " ) ; return 0 ; }
2010-03-27 16:05:02 +00:00
// Skip whitespace
SkipWhitespace ( ) ;
// Save position
const char * pStart = pPos ;
// Escaped? Go over '"'
2010-03-28 18:58:01 +00:00
if ( eRawType = = RCT_Escaped & & * pPos + + ! = ' " ' )
2009-05-08 13:28:41 +00:00
{ notFound ( " Escaped string " ) ; return 0 ; }
2010-03-27 16:05:02 +00:00
// Search end of string
size_t iLength = 0 ;
2010-03-28 18:58:01 +00:00
while ( ! TestStringEnd ( eRawType ) )
2010-03-27 16:05:02 +00:00
{
// Read a character (we're just counting atm)
2010-03-28 18:58:01 +00:00
if ( eRawType = = RCT_Escaped )
2010-03-27 16:05:02 +00:00
ReadEscapedChar ( ) ;
else
pPos + + ;
// Count it
iLength + + ;
}
// Reset position, return the length
pPos = pStart ;
return iLength ;
2009-05-08 13:28:41 +00:00
}
StdBuf StdCompilerINIRead : : ReadString ( size_t iLength , RawCompileType eRawType , bool fAppendNull )
{
2010-03-27 16:05:02 +00:00
// Excpect valid position
2010-03-28 18:58:01 +00:00
if ( ! pPos )
2009-05-08 13:28:41 +00:00
{ notFound ( " String " ) ; return StdBuf ( ) ; }
2010-03-27 16:05:02 +00:00
// Skip whitespace
SkipWhitespace ( ) ;
// Escaped? Go over '"'
2010-03-28 18:58:01 +00:00
if ( eRawType = = RCT_Escaped & & * pPos + + ! = ' " ' )
2009-05-08 13:28:41 +00:00
{ notFound ( " Escaped string " ) ; return StdBuf ( ) ; }
2010-03-27 16:05:02 +00:00
// Create buffer
StdBuf OutBuf ; OutBuf . New ( iLength + ( fAppendNull ? sizeof ( ' \0 ' ) : 0 ) ) ;
// Read
char * pOut = getMBufPtr < char > ( OutBuf ) ;
2010-03-28 18:58:01 +00:00
while ( iLength & & ! TestStringEnd ( eRawType ) )
2010-03-27 16:05:02 +00:00
{
// Read a character
2010-03-28 18:58:01 +00:00
if ( eRawType = = RCT_Escaped )
2010-03-27 16:05:02 +00:00
* pOut + + = ReadEscapedChar ( ) ;
else
* pOut + + = * pPos + + ;
// Count it
iLength - - ;
}
// Escaped: Go over '"'
2010-03-28 18:58:01 +00:00
if ( eRawType = = RCT_Escaped )
2010-03-27 16:05:02 +00:00
{
2010-03-28 18:58:01 +00:00
while ( * pPos ! = ' " ' )
2010-03-27 16:05:02 +00:00
{
2010-03-28 18:58:01 +00:00
if ( ! * pPos | | * pPos = = ' \n ' | | * pPos = = ' \r ' )
2009-05-08 13:28:41 +00:00
{
Warn ( " string not terminated! " ) ;
pPos - - ;
break ;
}
2010-03-27 16:05:02 +00:00
pPos + + ;
}
pPos + + ;
}
2009-05-08 13:28:41 +00:00
// Nothing read? Identifiers need to be non-empty
2010-03-28 18:58:01 +00:00
if ( pOut = = OutBuf . getData ( ) & & ( eRawType = = RCT_Idtf | | eRawType = = RCT_ID ) )
2009-05-08 13:28:41 +00:00
{ notFound ( " String " ) ; return StdBuf ( ) ; }
2010-03-27 16:05:02 +00:00
// Append null
2010-03-28 18:58:01 +00:00
if ( fAppendNull )
2010-03-27 16:05:02 +00:00
* pOut = ' \0 ' ;
// Shrink, if less characters were read
OutBuf . Shrink ( iLength ) ;
// Done
return OutBuf ;
2009-05-08 13:28:41 +00:00
}
char StdCompilerINIRead : : ReadEscapedChar ( )
{
2010-03-27 16:05:02 +00:00
// Catch some no-noes like \0, \n etc.
2010-03-28 18:58:01 +00:00
if ( * pPos > = 0 & & iscntrl ( ( unsigned char ) * pPos ) )
2009-05-08 13:28:41 +00:00
{
Warn ( " Nonprintable character found in string: %02x " , static_cast < unsigned char > ( * pPos ) ) ;
return * pPos ;
}
2010-03-27 16:05:02 +00:00
// Not escaped? Just return it
2010-03-28 18:58:01 +00:00
if ( * pPos ! = ' \\ ' ) return * pPos + + ;
2010-03-27 16:05:02 +00:00
// What type of escape?
2010-03-28 18:58:01 +00:00
switch ( * + + pPos )
2010-03-27 16:05:02 +00:00
{
case ' a ' : pPos + + ; return ' \a ' ;
case ' b ' : pPos + + ; return ' \b ' ;
case ' f ' : pPos + + ; return ' \f ' ;
case ' n ' : pPos + + ; return ' \n ' ;
case ' r ' : pPos + + ; return ' \r ' ;
case ' t ' : pPos + + ; return ' \t ' ;
case ' v ' : pPos + + ; return ' \v ' ;
case ' \' ' : pPos + + ; return ' \' ' ;
case ' " ' : pPos + + ; return ' " ' ;
case ' \\ ' : pPos + + ; return ' \\ ' ;
case ' ? ' : pPos + + ; return ' ? ' ;
case ' x ' :
// Treat '\x' as 'x' - damn special cases
2010-03-28 18:58:01 +00:00
if ( ! isxdigit ( ( unsigned char ) * + + pPos ) )
2010-03-27 16:05:02 +00:00
return ' x ' ;
else
{
// Read everything that looks like it might be hexadecimal - MSVC does it this way, so do not sue me.
int iCode = 0 ;
do
{ iCode = iCode * 16 + ( isdigit ( ( unsigned char ) * pPos ) ? * pPos - ' 0 ' : * pPos - ' a ' + 10 ) ; pPos + + ; }
2010-03-28 18:58:01 +00:00
while ( isxdigit ( ( unsigned char ) * pPos ) ) ;
2010-03-27 16:05:02 +00:00
// Done. Don't bother to check the range (we aren't doing anything mission-critical here, are we?)
return char ( iCode ) ;
}
default :
// Not octal? Let it pass through.
2010-03-28 18:58:01 +00:00
if ( ! isdigit ( ( unsigned char ) * pPos ) | | * pPos > = ' 8 ' )
2010-03-27 16:05:02 +00:00
return * pPos + + ;
else
{
// Read it the octal way.
int iCode = 0 ;
do
{ iCode = iCode * 8 + ( * pPos - ' 0 ' ) ; pPos + + ; }
2010-03-28 18:58:01 +00:00
while ( isdigit ( ( unsigned char ) * pPos ) & & * pPos < ' 8 ' ) ;
2010-03-27 16:05:02 +00:00
// Done. See above.
return char ( iCode ) ;
}
}
// unreachable
2009-05-08 13:28:41 +00:00
assert ( false ) ;
}
void StdCompilerINIRead : : notFound ( const char * szWhat )
{
excNotFound ( " %s expected " , szWhat ) ;
}
2009-06-12 18:52:21 +00:00
void StdCompilerWarnCallback ( void * pData , const char * szPosition , const char * szError )
2010-03-28 18:58:01 +00:00
{
2009-06-12 18:52:21 +00:00
const char * szName = reinterpret_cast < const char * > ( pData ) ;
2010-03-28 18:58:01 +00:00
if ( ! szPosition | | ! * szPosition )
2009-06-12 18:52:21 +00:00
DebugLogF ( " WARNING: %s (in %s) " , szError , szName ) ;
else
DebugLogF ( " WARNING: %s (in %s, %s) " , szError , szPosition , szName ) ;
2010-03-28 18:58:01 +00:00
}