// GetExtraOutputPath //------------------------------------------------------------------------------ void FunctionObjectList::GetExtraOutputPath( const AString * it, const AString * end, const char * option, AString & path ) const { const char * bodyStart = it->Get() + strlen( option ) + 1; // +1 for - or / const char * bodyEnd = it->GetEnd(); // if token is exactly matched then value is next token if ( bodyStart == bodyEnd ) { ++it; // handle missing next value if ( it == end ) { return; // we just pretend it doesn't exist and let the compiler complain } bodyStart = it->Get(); bodyEnd = it->GetEnd(); } // Strip quotes Args::StripQuotes( bodyStart, bodyEnd, path ); // If it's not already a path (i.e. includes filename.ext) then // truncate to just the path const char * lastSlash = path.FindLast( '\\' ); lastSlash = lastSlash ? lastSlash : path.FindLast( '/' ); lastSlash = lastSlash ? lastSlash : path.Get(); // no slash, means it's just a filename if ( lastSlash != ( path.GetEnd() - 1 ) ) { path.SetLength( uint32_t(lastSlash - path.Get()) ); } }
// WriteHeader //------------------------------------------------------------------------------ void SLNGenerator::WriteHeader( const AString & solutionVisualStudioVersion, const AString & solutionMinimumVisualStudioVersion ) { const char * defaultVersion = "14.0.22823.1"; // Visual Studio 2015 RC const char * defaultMinimumVersion = "10.0.40219.1"; // Visual Studio Express 2010 const char * version = ( solutionVisualStudioVersion.GetLength() > 0 ) ? solutionVisualStudioVersion.Get() : defaultVersion ; const char * minimumVersion = ( solutionMinimumVisualStudioVersion.GetLength() > 0 ) ? solutionMinimumVisualStudioVersion.Get() : defaultMinimumVersion ; const char * shortVersionStart = version; const char * shortVersionEnd = version; for ( ; *shortVersionEnd && *shortVersionEnd != '.' ; ++shortVersionEnd ); AStackString<> shortVersion( shortVersionStart, shortVersionEnd ); // header Write( "\r\n" ); // Deliberate blank line Write( "Microsoft Visual Studio Solution File, Format Version 12.00\r\n" ); Write( "# Visual Studio %s\r\n", shortVersion.Get() ); Write( "VisualStudioVersion = %s\r\n", version ); Write( "MinimumVisualStudioVersion = %s\r\n", minimumVersion ); }
// DirectoryCreate //------------------------------------------------------------------------------ /*static*/ bool FileIO::DirectoryCreate( const AString & path ) { #if defined( __WINDOWS__ ) if ( CreateDirectory( path.Get(), nullptr ) ) { return true; } // it failed - is it because it exists already? if ( GetLastError() == ERROR_ALREADY_EXISTS ) { return true; } #elif defined( __LINUX__ ) || defined( __APPLE__ ) umask( 0 ); // disable default creation mask mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO; // TODO:LINUX TODO:MAC Check these permissions if ( mkdir( path.Get(), mode ) == 0 ) { return true; // created ok } // failed to create - already exists? if ( errno == EEXIST ) { return true; } #else #error Unknown platform #endif // failed, probably missing intermediate folders or an invalid name return false; }
// GetFileInfo //------------------------------------------------------------------------------ /*static*/ bool FileIO::GetFileInfo( const AString & fileName, FileIO::FileInfo & info ) { #if defined( __WINDOWS__ ) WIN32_FILE_ATTRIBUTE_DATA fileAttribs; if ( GetFileAttributesEx( fileName.Get(), GetFileExInfoStandard, &fileAttribs ) ) { info.m_Name = fileName; info.m_Attributes = fileAttribs.dwFileAttributes; info.m_LastWriteTime = (uint64_t)fileAttribs.ftLastWriteTime.dwLowDateTime | ( (uint64_t)fileAttribs.ftLastWriteTime.dwHighDateTime << 32 ); info.m_Size = (uint64_t)fileAttribs.nFileSizeLow | ( (uint64_t)fileAttribs.nFileSizeHigh << 32 ); return true; } #elif defined( __APPLE__ ) || defined( __LINUX__ ) struct stat s; if ( stat( fileName.Get(), &s ) == 0 ) { info.m_Name = fileName; info.m_Attributes = s.st_mode; #if defined( __APPLE__ ) info.m_LastWriteTime = ( ( (uint64_t)s.st_mtimespec.tv_sec * 1000000000ULL ) + (uint64_t)s.st_mtimespec.tv_nsec ); #else info.m_LastWriteTime = ( ( (uint64_t)s.st_mtim.tv_sec * 1000000000ULL ) + (uint64_t)s.st_mtim.tv_nsec ); #endif info.m_Size = s.st_size; return true; } #endif return false; }
// GetFolderIndexFor //------------------------------------------------------------------------------ uint32_t ProjectGeneratorBase::GetFolderIndexFor( const AString & path ) { // Get the path exluding the file file or dir const char * lastSlash = path.FindLast( NATIVE_SLASH ); if ( ( lastSlash == nullptr ) || ( lastSlash == path.Get() ) ) { return 0; // no sub-path: put it in the root } // Search for existing folder AStackString<> folderPath( path.Get(), lastSlash ); for ( const Folder& folder : m_Folders ) { if ( folder.m_Path == folderPath ) { return (uint32_t)( &folder - m_Folders.Begin() ); // Found existing } } // Add new folder(s) recursively const uint32_t parentFolderIndex = GetFolderIndexFor( folderPath ); // Create new folder Folder f; f.m_Path = folderPath; m_Folders.Append( f ); const uint32_t folderIndex = (uint32_t)( m_Folders.GetSize() - 1 ); // Add to parent folder m_Folders[ parentFolderIndex ].m_Folders.Append( folderIndex ); return folderIndex; }
// CONSTRUCTOR //------------------------------------------------------------------------------ /*explicit*/ CachePlugin::CachePlugin( const AString & dllName ) : #if defined( __WINDOWS__ ) m_DLL( nullptr ), #endif m_InitFunc( nullptr ), m_ShutdownFunc( nullptr ), m_PublishFunc( nullptr ), m_RetrieveFunc( nullptr ), m_FreeMemoryFunc( nullptr ) { #if defined( __WINDOWS__ ) m_DLL = ::LoadLibrary( dllName.Get() ); if ( !m_DLL ) { FLOG_WARN( "Cache plugin '%s' load failed (0x%x).", dllName.Get(), ::GetLastError() ); return; } m_InitFunc = (CacheInitFunc) GetFunction( "CacheInit", "?CacheInit@@YA_NPEBD@Z" ); m_ShutdownFunc = (CacheShutdownFunc) GetFunction( "CacheShutdown", "?CacheShutdown@@YAXXZ" ); m_PublishFunc = (CachePublishFunc) GetFunction( "CachePublish", "?CachePublish@@YA_NPEBDPEBX_K@Z" ); m_RetrieveFunc = (CacheRetrieveFunc) GetFunction( "CacheRetrieve", "?CacheRetrieve@@YA_NPEBDAEAPEAXAEA_K@Z" ); m_FreeMemoryFunc= (CacheFreeMemoryFunc) GetFunction( "CacheFreeMemory", "?CacheFreeMemory@@YAXPEAX_K@Z" ); #elif defined( __APPLE__ ) ASSERT( false ); // TODO:MAC Implement CachePlugin #elif defined( __LINUX__ ) ASSERT( false ); // TODO:LINUX Implement CachePlugin #else #error Unknown platform #endif }
// GetFileLastWriteTime //------------------------------------------------------------------------------ /*static*/ uint64_t FileIO::GetFileLastWriteTime( const AString & fileName ) { #if defined( __WINDOWS__ ) WIN32_FILE_ATTRIBUTE_DATA fileAttribs; if ( GetFileAttributesEx( fileName.Get(), GetFileExInfoStandard, &fileAttribs ) ) { FILETIME ftWrite = fileAttribs.ftLastWriteTime; uint64_t lastWriteTime = (uint64_t)ftWrite.dwLowDateTime | ( (uint64_t)ftWrite.dwHighDateTime << 32 ); return lastWriteTime; } #elif defined( __APPLE__ ) struct stat st; if ( stat( fileName.Get(), &st ) == 0 ) { // OSX only supports setting filetimes at usec granularity // so if we ever receive times with sub-usec granularity // we will lose accuracy. ASSERT( ( st.st_mtimespec.tv_nsec % 1000 ) == 0 ); return ( ( (uint64_t)st.st_mtimespec.tv_sec * 1000000000ULL ) + (uint64_t)st.st_mtimespec.tv_nsec ); } #elif defined( __LINUX__ ) struct stat st; if ( stat( fileName.Get(), &st ) == 0 ) { return ( ( (uint64_t)st.st_mtim.tv_sec * 1000000000ULL ) + (uint64_t)st.st_mtim.tv_nsec ); } #else #error Unknown platform #endif return 0; }
// GetFolderPath //------------------------------------------------------------------------------ void VSProjectGenerator::GetFolderPath( const AString & fileName, AString & folder ) const { const AString * const bEnd = m_BasePaths.End(); for ( const AString * bIt = m_BasePaths.Begin(); bIt != bEnd; ++bIt ) { const AString & basePath = *bIt; const char * begin = fileName.Get(); const char * end = fileName.GetEnd(); if ( fileName.BeginsWithI( basePath ) ) { begin = fileName.Get() + basePath.GetLength(); const char * lastSlash = fileName.FindLast( BACK_SLASH ); end = ( lastSlash ) ? lastSlash : end; if ( begin < end ) { folder.Assign( begin, end ); return; } } } // no matching base path (use root) folder.Clear(); }
bool ReflectedProperty::FromString( const AString & buffer, int64_t * value ) { #if defined( __LINUX__ ) return ( sscanf_s( buffer.Get(), "%ld", value ) == 1 ); #else return ( sscanf_s( buffer.Get(), "%lld", value ) == 1 ); #endif }
// CompareI //------------------------------------------------------------------------------ int32_t AString::CompareI( const AString & other ) const { #if defined( __WINDOWS__ ) return _stricmp( m_Contents, other.Get() ); #elif defined( __APPLE__ ) || defined( __LINUX__ ) return strcasecmp( m_Contents, other.Get() ); #else #error Unknown platform #endif }
// FileMove //------------------------------------------------------------------------------ /*static*/ bool FileIO::FileMove( const AString & srcFileName, const AString & dstFileName ) { #if defined( __WINDOWS__ ) return ( TRUE == ::MoveFileEx( srcFileName.Get(), dstFileName.Get(), MOVEFILE_REPLACE_EXISTING ) ); #elif defined( __LINUX__ ) || defined( __APPLE__ ) return ( rename( srcFileName.Get(), dstFileName.Get() ) == 0 ); #else #error Unknown platform #endif }
bool ReflectedProperty::FromString( const AString & buffer, bool * value ) { if ( AString::StrNCmpI( buffer.Get(), "true", 4 ) == 0 ) { *value = true; return true; } if ( AString::StrNCmpI( buffer.Get(), "false", 5 ) == 0 ) { *value = false; return true; } return false; }
// StoreVariableStruct //------------------------------------------------------------------------------ bool BFFParser::StoreVariableStruct( const AString & name, const BFFIterator & valueStart, const BFFIterator & valueEnd, const BFFIterator & operatorIter, BFFStackFrame * frame ) { // are we concatenating? if ( *operatorIter == BFF_VARIABLE_CONCATENATION ) { // concatenation of structs not supported Error::Error_1027_CannotModify( operatorIter, name, BFFVariable::VAR_STRUCT, BFFVariable::VAR_ANY ); return false; } // create stack frame to capture variables BFFStackFrame stackFrame; // parse all the variables in the scope BFFParser subParser; BFFIterator subIter( valueStart ); subIter.SetMax( valueEnd.GetCurrent() ); // limit to closing token if ( subParser.Parse( subIter ) == false ) { return false; // error will be emitted by Parse } // get variables defined in the scope const Array< const BFFVariable * > & structMembers = stackFrame.GetLocalVariables(); // Register this variable BFFStackFrame::SetVarStruct( name, structMembers, frame ? frame : stackFrame.GetParent() ); FLOG_INFO( "Registered <struct> variable '%s' with %u members", name.Get(), structMembers.GetSize() ); return true; }
/*static*/ void FileIO::WorkAroundForWindowsFilePermissionProblem( const AString & fileName ) { // Sometimes after closing a file, subsequent operations on that file will // fail. For example, trying to set the file time, or even another process // opening the file. // // This seems to be a known issue in windows, with multiple potential causes // like Virus scanners and possibly the behaviour of the kernel itself. // // A work-around for this problem is to attempt to open a file we just closed. // This will sometimes fail, but if we retry until it succeeds, we avoid the // problem on the subsequent operation. FileStream f; Timer timer; while ( f.Open( fileName.Get() ) == false ) { Thread::Sleep( 1 ); // timeout so we don't get stuck in here forever if ( timer.GetElapsed() > 1.0f ) { ASSERT( false && "WorkAroundForWindowsFilePermissionProblem Failed!" ); return; } } f.Close(); }
// CreateTempFile //------------------------------------------------------------------------------ /*static*/ bool WorkerThread::CreateTempFile( const AString & tmpFileName, FileStream & file ) { ASSERT( tmpFileName.IsEmpty() == false ); ASSERT( PathUtils::IsFullPath( tmpFileName ) ); return file.Open( tmpFileName.Get(), FileStream::WRITE_ONLY ); }
// Error_1100_AlreadyDefined //------------------------------------------------------------------------------ /*static*/ void Error::Error_1100_AlreadyDefined( const BFFIterator & iter, const Function * function, const AString & name ) { FormatError( iter, 1100u, function, "Target '%s' already defined.", name.Get() ); }
// Error_1101_MissingProperty //------------------------------------------------------------------------------ /*static*/ void Error::Error_1101_MissingProperty( const BFFIterator & iter, const Function * function, const AString & name ) { FormatError( iter, 1101u, function, "Missing required property '%s'.", name.Get() ); }
// SetCurrentDir //------------------------------------------------------------------------------ /*static*/ bool FileIO::SetCurrentDir( const AString & dir ) { #if defined( __WINDOWS__ ) // Windows can have upper or lower case letters in the path for the drive // letter. The case may be important for the user, but setting the current // dir with only a change in case is ignored. // To ensure we have the requested case, we have to change dir to another // location, and then the location we want. // get another valid location to set as the dir // (we'll use the windows directory) char otherFolder[ 512 ]; otherFolder[ 0 ] = 0; UINT len = ::GetWindowsDirectory( otherFolder, 512 ); if ( ( len == 0 ) || ( len > 511 ) ) { return false; } // handle the case where the user actually wants the windows dir if ( _stricmp( otherFolder, dir.Get() ) == 0 ) { // use the root of the drive containing the windows dir otherFolder[ 3 ] = 0; } // set "other" dir if ( ::SetCurrentDirectory( otherFolder ) == FALSE ) { return false; } // set the actual directory we want if ( ::SetCurrentDirectory( dir.Get() ) == TRUE ) { return true; } #elif defined( __LINUX__ ) || defined( __APPLE__ ) if ( chdir( dir.Get() ) == 0 ) { return true; } #else #error Unknown platform #endif return false; }
// Error_1033_ErrorReadingInclude //------------------------------------------------------------------------------ /*static*/ void Error::Error_1033_ErrorReadingInclude( const BFFIterator & iter, const AString & include, uint32_t errorCode ) { FormatError( iter, 1033u, nullptr, "Error reading include '%s' (Error: %u).", include.Get(), errorCode ); }
// Error_1029_VariableForSubstitutionIsNotAString //------------------------------------------------------------------------------ /*static*/ void Error::Error_1029_VariableForSubstitutionIsNotAString( const BFFIterator & iter, const AString & variableName, BFFVariable::VarType varType ) { FormatError( iter, 1029u, nullptr, "Variable for substitution '%s' is not a string (Type: <%s>).", variableName.Get(), BFFVariable::GetTypeName( varType ) ); }
// WritePGItem //------------------------------------------------------------------------------ void VSProjectGenerator::WritePGItem( const char * xmlTag, const AString & value ) { if ( value.IsEmpty() ) { return; } Write( " <%s>%s</%s>\n", xmlTag, value.Get(), xmlTag ); }
// Publish //------------------------------------------------------------------------------ /*virtual*/ bool CachePlugin::Publish( const AString & cacheId, const void * data, size_t dataSize ) { if ( m_PublishFunc ) { return (*m_PublishFunc)( cacheId.Get(), data, dataSize ); } return false; }
bool ReflectedProperty::FromString( const AString & buffer, Mat44 * value ) { return ( sscanf_s( buffer.Get(), "%f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f", &value->col0.x, &value->col0.y, &value->col0.z, &value->col0.z, &value->col1.x, &value->col1.y, &value->col1.z, &value->col1.z, &value->col2.x, &value->col2.y, &value->col2.z, &value->col2.z, &value->col3.x, &value->col3.y, &value->col3.z, &value->col3.z ) == 16 ); }
// StoreVariableInt //------------------------------------------------------------------------------ bool BFFParser::StoreVariableInt( const AString & name, int value, BFFStackFrame * frame ) { BFFStackFrame::SetVarInt( name, value, frame ); FLOG_INFO( "Registered <int> variable '%s' with value '%i'", name.Get(), value ); return true; }
// GetRelativePath //------------------------------------------------------------------------------ /*static*/ void ToolManifest::GetRelativePath( const AString & mainExe, const AString & otherFile, AString & otherFileRelativePath ) { // determine primary root AStackString<> primaryPath( mainExe.Get(), mainExe.FindLast( NATIVE_SLASH ) + 1 ); // include backslash if ( otherFile.BeginsWithI( primaryPath ) ) { // file is in sub dir on master machine, so store with same relative location otherFileRelativePath += ( otherFile.Get() + primaryPath.GetLength() ); } else { // file is in some completely other directory, so put in same place as exe const char * lastSlash = otherFile.FindLast( NATIVE_SLASH ); otherFileRelativePath += ( lastSlash ? lastSlash + 1 : otherFile.Get() ); } }
// StoreVariableString //------------------------------------------------------------------------------ bool BFFParser::StoreVariableString( const AString & name, const BFFIterator & valueStart, const BFFIterator & valueEnd, const BFFIterator & operatorIter, BFFStackFrame * frame ) { // unescape and subsitute embedded variables AStackString< 2048 > value; if ( PerformVariableSubstitutions( valueStart, valueEnd, value ) == false ) { return false; } // are we concatenating? const BFFVariable * varToConcat = nullptr; if ( *operatorIter == BFF_VARIABLE_CONCATENATION ) { // find existing varToConcat = BFFStackFrame::GetVar( name, frame ); if ( varToConcat == nullptr ) { Error::Error_1026_VariableNotFoundForConcatenation( operatorIter, name ); return false; } // make sure types are compatible if ( varToConcat->IsString() ) { // OK - can concat String to String AStackString< 1024 > finalValue( varToConcat->GetString() ); finalValue += value; BFFStackFrame::SetVarString( name, finalValue, frame ); FLOG_INFO( "Appended '%s' to <String> variable '%s' with result '%s'", value.Get(), name.Get(), finalValue.Get() ); return true; } else if ( varToConcat->IsArrayOfStrings() ) { // OK - can concat String to ArrayOfStrings Array< AString > finalValues( varToConcat->GetArrayOfStrings().GetSize() + 1, false ); finalValues = varToConcat->GetArrayOfStrings(); finalValues.Append( value ); BFFStackFrame::SetVarArrayOfStrings( name, finalValues, frame ); FLOG_INFO( "Appended '%s' to <ArrayOfStrings> variable '%s' with result of %i items", value.Get(), name.Get(), finalValues.GetSize() ); return true; } else { Error::Error_1027_CannotConcatenate( operatorIter, name, varToConcat->GetType(), BFFVariable::VAR_STRING ); return false; } } // handle regular assignment of string BFFStackFrame::SetVarString( name, value, frame ); FLOG_INFO( "Registered <string> variable '%s' with value '%s'", name.Get(), value.Get() ); return true; }
// Error_1104_MissingTarget //------------------------------------------------------------------------------ /*static*/ void Error::Error_1104_TargetNotDefined( const BFFIterator & iter, const Function * function, const char * propertyName, const AString & name ) { FormatError( iter, 1104u, function, "'%s' ('%s') is not defined.", propertyName, name.Get() ); }
// Error_1031_UnexpectedCharFollowingDirectiveName //------------------------------------------------------------------------------ /*static*/ void Error::Error_1031_UnexpectedCharFollowingDirectiveName( const BFFIterator & iter, const AString & directive, char expectedChar ) { FormatError( iter, 1031u, nullptr, "Unknown char '%c' following '%s' directive. (Expected '%c').", *iter, directive.Get(), expectedChar ); }
// CONSTRUCTOR //------------------------------------------------------------------------------ FileNode::FileNode( const AString & fileName, uint32_t controlFlags ) : Node( fileName, Node::FILE_NODE, controlFlags ) { ASSERT( fileName.EndsWith( "\\" ) == false ); ASSERT( ( fileName.FindLast( ':' ) == nullptr ) || ( fileName.FindLast( ':' ) == ( fileName.Get() + 1 ) ) ); m_LastBuildTimeMs = 1; // very little work required }
// BeginsWithI //------------------------------------------------------------------------------ bool AString::BeginsWithI( const AString & string ) const { uint32_t otherLen = string.GetLength(); if ( otherLen > GetLength() ) { return false; } return ( StrNCmpI( m_Contents, string.Get(), otherLen ) == 0 ); }