/* =========================================================================== Doom 3 GPL Source Code Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). Doom 3 Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Doom 3 Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Doom 3 Source Code. If not, see . In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. =========================================================================== */ #include "sys/platform.h" #include "TypeInfo/TypeInfoGen.h" #define TYPE_INFO_GEN_VERSION "1.0" /* ================ idTypeInfoGen::idTypeInfoGen ================ */ idTypeInfoGen::idTypeInfoGen( void ) { } /* ================ idTypeInfoGen::~idTypeInfoGen ================ */ idTypeInfoGen::~idTypeInfoGen( void ) { constants.DeleteContents( true ); enums.DeleteContents( true ); classes.DeleteContents( true ); } /* ================ idTypeInfoGen::GetInheritance ================ */ int idTypeInfoGen::GetInheritance( const char *typeName ) const { int i; for ( i = 0; i < classes.Num(); i++ ) { if ( classes[i]->typeName.Cmp( typeName ) == 0 ) { if ( classes[i]->superType[0] != '\0' ) { return 1 + GetInheritance( classes[i]->superType ); } break; } } return 0; } /* ================ idTypeInfoGen::EvaluateIntegerString ================ */ int idTypeInfoGen::EvaluateIntegerString( const idStr &string ) { idParser src; idStr evalString; if ( string.Find( "::" ) != -1 ) { return 0; } evalString = "$evalint(" + string + ")"; src.LoadMemory( evalString, evalString.Length(), "eval integer" ); return src.ParseInt(); } /* ================ idTypeInfoGen::EvaluateFloatString ================ */ float idTypeInfoGen::EvaluateFloatString( const idStr &string ) { idParser src; idStr evalString; if ( string.Find( "::" ) != -1 ) { return 0.0f; } evalString = "$evalfloat(" + string + ")"; src.LoadMemory( evalString, evalString.Length(), "eval float" ); return src.ParseFloat(); } /* ================ idTypeInfoGen::FindConstant ================ */ idConstantInfo *idTypeInfoGen::FindConstant( const char *name ) { int i; for ( i = 0; i < constants.Num(); i++ ) { if ( constants[i]->name.Cmp( name ) == 0 ) { return constants[i]; } } return NULL; } /* ================ idTypeInfoGen::GetIntegerConstant ================ */ int idTypeInfoGen::GetIntegerConstant( const char *scope, const char *name, idParser &src ) { idConstantInfo *constant = FindConstant( idStr( scope ) + name ); if ( constant == NULL ) { constant = FindConstant( name ); } if ( constant ) { return EvaluateIntegerString( constant->value ); } src.Warning( "unknown value '%s' in constant expression", name ); return 0; } /* ================ idTypeInfoGen::GetFloatConstant ================ */ float idTypeInfoGen::GetFloatConstant( const char *scope, const char *name, idParser &src ) { idConstantInfo *constant = FindConstant( idStr( scope ) + name ); if ( constant == NULL ) { constant = FindConstant( name ); } if ( constant ) { return EvaluateFloatString( constant->value ); } src.Warning( "unknown value '%s' in constant expression", name ); return 0; } /* ================ idTypeInfoGen::ParseArraySize ================ */ int idTypeInfoGen::ParseArraySize( const char *scope, idParser &src ) { idToken token; idStr sizeString, constantString; int size, totalSize; if ( !src.CheckTokenString( "[" ) ) { return 0; } totalSize = 1; sizeString = ""; while( src.ReadToken( &token ) ) { if ( token == "]" ) { if ( sizeString.Length() ) { size = EvaluateIntegerString( sizeString ); if ( size ) { totalSize *= size; } sizeString = ""; } if ( !src.CheckTokenString( "[" ) ) { break; } } else if ( token.type == TT_NAME ) { constantString = token; while( src.CheckTokenString( "::" ) ) { src.ExpectTokenType( TT_NAME, 0, &token ); constantString += "::" + token; } sizeString += va( "%d", GetIntegerConstant( scope, constantString, src ) ); } else { sizeString += token; } } return totalSize; } /* ================ idTypeInfoGen::ParseConstantValue ================ */ void idTypeInfoGen::ParseConstantValue( const char *scope, idParser &src, idStr &value ) { idToken token; idStr constantString; int indent = 0; while( src.ReadToken( &token ) ) { if ( token == "(" ) { indent++; } else if ( token == ")" ) { indent--; } else if ( indent == 0 && ( token == ";" || token == "," || token == "}" ) ) { src.UnreadToken( &token ); break; } else if ( token.type == TT_NAME ) { constantString = token; while( src.CheckTokenString( "::" ) ) { src.ExpectTokenType( TT_NAME, 0, &token ); constantString += "::" + token; } value += va( "%d", GetIntegerConstant( scope, constantString, src ) ); continue; } value += token; } } /* ================ idTypeInfoGen::ParseEnumType ================ */ idEnumTypeInfo *idTypeInfoGen::ParseEnumType( const char *scope, bool isTemplate, bool typeDef, idParser &src ) { int value; idToken token; idEnumTypeInfo *typeInfo; idEnumValueInfo enumValue; idStr valueString; typeInfo = new idEnumTypeInfo; typeInfo->scope = scope; typeInfo->isTemplate = isTemplate; if ( src.CheckTokenType( TT_NAME, 0, &token ) ) { typeInfo->typeName = token; typeInfo->unnamed = false; } else { sprintf( typeInfo->typeName, "enum_%d", enums.Num() ); typeInfo->unnamed = true; } if ( !src.CheckTokenString( "{" ) ) { src.UnreadToken( &token ); delete typeInfo; return NULL; } value = -1; while( src.ExpectTokenType( TT_NAME, 0, &token ) ) { enumValue.name = token; if ( src.CheckTokenString( "=" ) ) { idStr valueString; ParseConstantValue( scope, src, valueString ); if ( valueString.Length() ) { value = EvaluateIntegerString( valueString ); } } else { value++; } enumValue.value = value; typeInfo->values.Append( enumValue ); // add a constant for the enum value idConstantInfo *constantInfo = new idConstantInfo; constantInfo->name = scope + enumValue.name; constantInfo->type = "int"; constantInfo->value = va( "%d", value ); constants.Append( constantInfo ); src.CheckTokenString( "," ); if ( src.CheckTokenString( "}" ) ) { break; } } if ( typeDef ) { if ( src.CheckTokenType( TT_NAME, 0, &token ) ) { typeInfo->typeName = token; typeInfo->unnamed = false; } src.ExpectTokenString( ";" ); } //common->Printf( "enum %s%s\n", typeInfo->scope.c_str(), typeInfo->typeName.c_str() ); return typeInfo; } /* ================ idTypeInfoGen::ParseClassType ================ */ idClassTypeInfo *idTypeInfoGen::ParseClassType( const char *scope, const char *templateArgs, bool isTemplate, bool typeDef, idParser &src ) { idToken token; idClassTypeInfo *typeInfo; typeInfo = new idClassTypeInfo; typeInfo->scope = scope; typeInfo->isTemplate = isTemplate; if ( src.CheckTokenType( TT_NAME, 0, &token ) ) { typeInfo->typeName = token + templateArgs; typeInfo->unnamed = false; } else { sprintf( typeInfo->typeName, "class_%d%s", classes.Num(), templateArgs ); typeInfo->unnamed = true; } if ( src.CheckTokenString( ":" ) ) { if ( !src.ExpectTokenType( TT_NAME, 0, &token ) ) { delete typeInfo; return NULL; } while( token == "public" || token == "protected" || token == "private" ) { if ( !src.ExpectTokenType( TT_NAME, 0, &token ) ) { delete typeInfo; return NULL; } typeInfo->superType = token; // read template arguments if ( src.CheckTokenString( "<" ) ) { int indent = 1; typeInfo->superType += "< "; while( src.ReadToken( &token ) ) { if ( token == "<" ) { indent++; } else if ( token == ">" ) { indent--; if ( indent == 0 ) { break; } } typeInfo->superType += token + " "; } typeInfo->superType += ">"; } // check for multiple inheritance if ( !src.CheckTokenString( "," ) ) { break; } if ( !src.ExpectTokenType( TT_NAME, 0, &token ) ) { delete typeInfo; return NULL; } src.Warning( "multiple inheritance not supported for '%s%s'", typeInfo->scope.c_str(), typeInfo->typeName.c_str() ); } } if ( !src.CheckTokenString( "{" ) ) { src.UnreadToken( &token ); delete typeInfo; return NULL; } ParseScope( typeInfo->scope + typeInfo->typeName + "::", typeInfo->isTemplate, src, typeInfo ); if ( typeDef ) { if ( src.CheckTokenType( TT_NAME, 0, &token ) ) { typeInfo->typeName = token + templateArgs; typeInfo->unnamed = false; } src.ExpectTokenString( ";" ); } //common->Printf( "class %s%s : %s\n", typeInfo->scope.c_str(), typeInfo->typeName.c_str(), typeInfo->superType.c_str() ); return typeInfo; } /* ================ idTypeInfoGen::ParseScope ================ */ void idTypeInfoGen::ParseScope( const char *scope, bool isTemplate, idParser &src, idClassTypeInfo *typeInfo ) { int indent; idToken token; idClassTypeInfo *classInfo; idEnumTypeInfo *enumInfo; idStr varType; bool isConst = false; bool isStatic = false; indent = 1; while( indent ) { if ( !src.ReadToken( &token ) ) { break; } if ( token == "{" ) { do { if ( token == "{" ) { indent++; } else if ( token == "}" ) { indent--; } varType += token + " "; } while( indent > 1 && src.ReadToken( &token ) ); } else if ( token == "}" ) { assert( indent == 1 ); indent--; } else if ( token == "<" ) { do { if ( token == "<" ) { indent++; } else if ( token == ">" ) { indent--; } varType += token + " "; } while( indent > 1 && src.ReadToken( &token ) ); } else if ( token == ";" ) { varType = ""; isConst = false; isStatic = false; } else if ( token == "public" || token == "protected" || token == "private" ) { if ( !src.ExpectTokenString( ":" ) ) { break; } varType = ""; isConst = false; isStatic = false; } else if ( token == "friend" ) { // skip friend classes/methods while( src.ReadToken( &token ) ) { if ( token == "{" ) { indent++; } else if ( token == "}" ) { indent--; if ( indent == 1 ) { break; } } else if ( token == ";" && indent == 1 ) { break; } } varType = ""; isConst = false; isStatic = false; } else if ( token == "template" ) { varType = ""; if ( src.CheckTokenString( "<" ) ) { int indent = 1; varType += "< "; while( src.ReadToken( &token ) ) { if ( token == "<" ) { indent++; } else if ( token == ">" ) { indent--; if ( indent == 0 ) { break; } } varType += token + " "; } varType += ">"; } if ( src.CheckTokenString( "class" ) ) { // parse template class classInfo = ParseClassType( scope, varType, true, false, src ); if ( classInfo ) { classes.Append( classInfo ); } } else { // skip template methods while( src.ReadToken( &token ) ) { if ( token == "{" ) { indent++; } else if ( token == "}" ) { indent--; if ( indent == 1 ) { break; } } else if ( token == ";" && indent == 1 ) { break; } } } varType = ""; isConst = false; isStatic = false; } else if ( token == "namespace" ) { // parse namespace classInfo = ParseClassType( scope, "", isTemplate, false, src ); delete classInfo; } else if ( token == "class" ) { // parse class classInfo = ParseClassType( scope, "", isTemplate, false, src ); if ( classInfo ) { classes.Append( classInfo ); } } else if ( token == "struct" ) { // parse struct classInfo = ParseClassType( scope, "", isTemplate, false, src ); if ( classInfo ) { classes.Append( classInfo ); varType = classInfo->scope + classInfo->typeName; } } else if ( token == "union" ) { // parse union classInfo = ParseClassType( scope, "", isTemplate, false, src ); if ( classInfo ) { classes.Append( classInfo ); } } else if ( token == "enum" ) { // parse enum enumInfo = ParseEnumType( scope, isTemplate, false, src ); if ( enumInfo ) { enums.Append( enumInfo ); varType = enumInfo->scope + enumInfo->typeName; } } else if ( token == "typedef" ) { if ( token == "class" ) { // parse typedef class classInfo = ParseClassType( scope, "", isTemplate, true, src ); if ( classInfo ) { classes.Append( classInfo ); } } else if ( src.CheckTokenString( "struct" ) ) { // parse typedef struct classInfo = ParseClassType( scope, "", isTemplate, true, src ); if ( classInfo ) { classes.Append( classInfo ); } } else if ( src.CheckTokenString( "union" ) ) { // parse typedef union classInfo = ParseClassType( scope, "", isTemplate, true, src ); if ( classInfo ) { classes.Append( classInfo ); } } else if ( src.CheckTokenString( "enum" ) ) { // parse typedef enum enumInfo = ParseEnumType( scope, isTemplate, true, src ); if ( enumInfo ) { enums.Append( enumInfo ); } } else { // skip other typedefs while( src.ReadToken( &token ) ) { if ( token == "{" ) { indent++; } else if ( token == "}" ) { indent--; } else if ( token == ";" && indent == 1 ) { break; } } } varType = ""; isConst = false; isStatic = false; } else if ( token == "const" ) { varType += token + " "; isConst = true; } else if ( token == "static" ) { varType += token + " "; isStatic = true; } else if ( token.type == TT_NAME ) { assert( indent == 1 ); // if this is a class operator if ( token == "operator" ) { while( src.ReadToken( &token ) ) { if ( token == "(" ) { src.UnreadToken( &token ); break; } } } // if this is a class method if ( src.CheckTokenString( "(" ) ) { indent++; while( indent > 1 && src.ReadToken( &token ) ) { if ( token == "(" ) { indent++; } else if ( token == ")" ) { indent--; } } if ( src.CheckTokenString( "(" ) ) { indent++; while( indent > 1 && src.ReadToken( &token ) ) { if ( token == "(" ) { indent++; } else if ( token == ")" ) { indent--; } } } if ( src.CheckTokenString( "const" ) ) { } if ( src.CheckTokenString( "=" ) ) { src.ExpectTokenString( "0" ); } else if ( src.CheckTokenString( "{" ) ) { indent++; while( indent > 1 && src.ReadToken( &token ) ) { if ( token == "{" ) { indent++; } else if ( token == "}" ) { indent--; } } } varType = ""; isConst = false; isStatic = false; } else if ( ( isStatic || isConst ) && src.CheckTokenString( "=" ) ) { // constant idConstantInfo *constantInfo = new idConstantInfo; constantInfo->name = scope + token; constantInfo->type = varType; constantInfo->type.StripTrailing( ' ' ); ParseConstantValue( scope, src, constantInfo->value ); constants.Append( constantInfo ); } else if ( isStatic ) { // static class variable varType += token + " "; } else { // check for class variables while( 1 ) { int arraySize = ParseArraySize( scope, src ); if ( arraySize ) { idClassVariableInfo var; var.name = token; var.type = varType; var.type.StripTrailing( ' ' ); var.type += va( "[%d]", arraySize ); var.bits = 0; typeInfo->variables.Append( var ); if ( !src.CheckTokenString( "," ) ) { varType = ""; isConst = false; isStatic = false; break; } varType.StripTrailing( "* " ); } else { int bits = 0; if ( src.CheckTokenString( ":" ) ) { idToken bitSize; src.ExpectTokenType( TT_NUMBER, TT_INTEGER, &bitSize ); bits = bitSize.GetIntValue(); } if ( src.CheckTokenString( "," ) ) { idClassVariableInfo var; var.name = token; var.type = varType; var.type.StripTrailing( ' ' ); var.bits = bits; typeInfo->variables.Append( var ); varType.StripTrailing( "* " ); } else if ( src.CheckTokenString( ";" ) ) { idClassVariableInfo var; var.name = token; var.type = varType; var.type.StripTrailing( ' ' ); var.bits = bits; typeInfo->variables.Append( var ); varType = ""; isConst = false; isStatic = false; break; } else { varType += token + " "; break; } } while( src.CheckTokenString( "*" ) ) { varType += "* "; } if ( !src.ExpectTokenType( TT_NAME, 0, &token ) ) { break; } } } } else { varType += token + " "; } } } /* ================ idTypeInfoGen::AddDefine ================ */ void idTypeInfoGen::AddDefine( const char *define ) { defines.Append( define ); } /* ================ idTypeInfoGen::CreateTypeInfo ================ */ void idTypeInfoGen::CreateTypeInfo( const char *path ) { int i, j, inheritance; idStr fileName; idFileList *files; idParser src; common->Printf( "Type Info Generator v"TYPE_INFO_GEN_VERSION" (c) 2004 id Software\n" ); common->Printf( "%s\n", path ); files = fileSystem->ListFilesTree( path, ".cpp" ); for ( i = 0; i < files->GetNumFiles(); i++ ) { fileName = fileSystem->RelativePathToOSPath( files->GetFile( i ) ); common->Printf( "processing '%s' for type info...\n", fileName.c_str() ); if ( !src.LoadFile( fileName, true ) ) { common->Warning( "couldn't load %s", fileName.c_str() ); continue; } src.SetFlags( LEXFL_NOBASEINCLUDES ); for ( j = 0; j < defines.Num(); j++ ) { src.AddDefine( defines[j] ); } idClassTypeInfo *typeInfo = new idClassTypeInfo; ParseScope( "", false, src, typeInfo ); delete typeInfo; src.FreeSource(); break; } fileSystem->FreeFileList( files ); numTemplates = 0; for ( i = 0; i < classes.Num(); i++ ) { if ( classes[i]->isTemplate ) { numTemplates++; } } maxInheritance = 0; maxInheritanceClass = ""; for ( i = 0; i < classes.Num(); i++ ) { inheritance = GetInheritance( classes[i]->typeName ); if ( inheritance > maxInheritance ) { maxInheritance = inheritance; maxInheritanceClass = classes[i]->typeName; } } common->Printf( "%d constants\n", constants.Num() ); common->Printf( "%d enums\n", enums.Num() ); common->Printf( "%d classes/structs/unions\n", classes.Num() ); common->Printf( "%d templates\n", numTemplates ); common->Printf( "%d max inheritance level for '%s'\n", maxInheritance, maxInheritanceClass.c_str() ); } /* ================ CleanName ================ */ void CleanName( idStr &name ) { name.Replace( "::", "_" ); name.Replace( " , ", "_" ); name.Replace( "< ", "_" ); name.Replace( " >", "_" ); name.Replace( " ", "_" ); } /* ================ idTypeInfoGen::WriteTypeInfo ================ */ void idTypeInfoGen::WriteTypeInfo( const char *fileName ) const { int i, j; idStr path, define; idFile *file; path = fileSystem->RelativePathToOSPath( fileName ); file = fileSystem->OpenExplicitFileWrite( path ); if ( !file ) { common->Warning( "couldn't open %s", path.c_str() ); return; } common->Printf( "writing %s...\n", path.c_str() ); path.ExtractFileName( define ); define.Replace( ".", "_" ); define.ToUpper(); file->WriteFloatString( "\n" "#ifndef __%s__\n" "#define __%s__\n" "\n" "/*\n" "===================================================================================\n" "\n" "\tThis file has been generated with the Type Info Generator v"TYPE_INFO_GEN_VERSION" (c) 2004 id Software\n" "\n" "\t%d constants\n" "\t%d enums\n" "\t%d classes/structs/unions\n" "\t%d templates\n" "\t%d max inheritance level for '%s'\n" "\n" "===================================================================================\n" "*/\n" "\n", define.c_str(), define.c_str(), constants.Num(), enums.Num(), classes.Num(), numTemplates, maxInheritance, maxInheritanceClass.c_str() ); file->WriteFloatString( "typedef struct {\n" "\t" "const char * name;\n" "\t" "const char * type;\n" "\t" "const char * value;\n" "} constantInfo_t;\n" "\n" "typedef struct {\n" "\t" "const char * name;\n" "\t" "int value;\n" "} enumValueInfo_t;\n" "\n" "typedef struct {\n" "\t" "const char * typeName;\n" "\t" "const enumValueInfo_t * values;\n" "} enumTypeInfo_t;\n" "\n" "typedef struct {\n" "\t" "const char * type;\n" "\t" "const char * name;\n" "\t" "int offset;\n" "\t" "int size;\n" "} classVariableInfo_t;\n" "\n" "typedef struct {\n" "\t" "const char * typeName;\n" "\t" "const char * superType;\n" "\t" "int size;\n" "\t" "const classVariableInfo_t * variables;\n" "} classTypeInfo_t;\n" "\n" ); // constants file->WriteFloatString( "static constantInfo_t constantInfo[] = {\n" ); for ( i = 0; i < constants.Num(); i++ ) { idConstantInfo *info = constants[i]; file->WriteFloatString( "\t{ \"%s\", \"%s\", \"%s\" },\n", info->type.c_str(), info->name.c_str(), info->value.c_str() ); } file->WriteFloatString( "\t{ NULL, NULL, NULL }\n" ); file->WriteFloatString( "};\n\n" ); // enum values for ( i = 0; i < enums.Num(); i++ ) { idEnumTypeInfo *info = enums[i]; idStr typeInfoName = info->scope + info->typeName; CleanName( typeInfoName ); file->WriteFloatString( "static enumValueInfo_t %s_typeInfo[] = {\n", typeInfoName.c_str() ); for ( j = 0; j < info->values.Num(); j++ ) { if ( info->isTemplate ) { file->WriteFloatString( "//" ); } file->WriteFloatString( "\t{ \"%s\", %d },\n", info->values[j].name.c_str(), info->values[j].value ); } file->WriteFloatString( "\t{ NULL, 0 }\n" ); file->WriteFloatString( "};\n\n" ); } // enums file->WriteFloatString( "static enumTypeInfo_t enumTypeInfo[] = {\n" ); for ( i = 0; i < enums.Num(); i++ ) { idEnumTypeInfo *info = enums[i]; idStr typeName = info->scope + info->typeName; idStr typeInfoName = typeName; CleanName( typeInfoName ); if ( info->isTemplate ) { file->WriteFloatString( "//" ); } file->WriteFloatString( "\t{ \"%s\", %s_typeInfo },\n", typeName.c_str(), typeInfoName.c_str() ); } file->WriteFloatString( "\t{ NULL, NULL }\n" ); file->WriteFloatString( "};\n\n" ); // class variables for ( i = 0; i < classes.Num(); i++ ) { idClassTypeInfo *info = classes[i]; idStr typeName = info->scope + info->typeName; idStr typeInfoName = typeName; CleanName( typeInfoName ); file->WriteFloatString( "static classVariableInfo_t %s_typeInfo[] = {\n", typeInfoName.c_str() ); for ( j = 0; j < info->variables.Num(); j++ ) { const char *varName = info->variables[j].name.c_str(); const char *varType = info->variables[j].type.c_str(); if ( info->unnamed || info->isTemplate || info->variables[j].bits != 0 ) { file->WriteFloatString( "//" ); } file->WriteFloatString( "\t{ \"%s\", \"%s\", (int)(&((%s *)0)->%s), sizeof( ((%s *)0)->%s ) },\n", varType, varName, typeName.c_str(), varName, typeName.c_str(), varName ); } file->WriteFloatString( "\t{ NULL, 0 }\n" ); file->WriteFloatString( "};\n\n" ); } // classes file->WriteFloatString( "static classTypeInfo_t classTypeInfo[] = {\n" ); for ( i = 0; i < classes.Num(); i++ ) { idClassTypeInfo *info = classes[i]; idStr typeName = info->scope + info->typeName; idStr typeInfoName = typeName; CleanName( typeInfoName ); if ( info->unnamed || info->isTemplate ) { file->WriteFloatString( "//" ); } file->WriteFloatString( "\t{ \"%s\", \"%s\", sizeof(%s), %s_typeInfo },\n", typeName.c_str(), info->superType.c_str(), typeName.c_str(), typeInfoName.c_str() ); } file->WriteFloatString( "\t{ NULL, NULL, 0, NULL }\n" ); file->WriteFloatString( "};\n\n" ); file->WriteFloatString( "#endif /* !__%s__ */\n", define.c_str() ); fileSystem->CloseFile( file ); }