Example #1
0
// ProcessEnvironment
//------------------------------------------------------------------------------
void FunctionSettings::ProcessEnvironment( const Array< AString > & envStrings ) const
{
    // the environment string is used in windows as a double-null terminated string
    // so convert our array to a single buffer

    // work out space required
    uint32_t size = 0;
    for ( uint32_t i=0; i<envStrings.GetSize(); ++i )
    {
        size += envStrings[ i ].GetLength() + 1; // string len inc null
    }

    // allocate space
    AutoPtr< char > envString( (char *)ALLOC( size + 1 ) ); // +1 for extra double-null

    // while iterating, extract the LIB environment variable (if there is one)
    AStackString<> libEnvVar;

    // copy strings end to end
    char * dst = envString.Get();
    for ( uint32_t i=0; i<envStrings.GetSize(); ++i )
    {
        if ( envStrings[ i ].BeginsWith( "LIB=" ) )
        {
            libEnvVar.Assign( envStrings[ i ].Get() + 4, envStrings[ i ].GetEnd() );
        }

        const uint32_t thisStringLen = envStrings[ i ].GetLength();
        AString::Copy( envStrings[ i ].Get(), dst, thisStringLen );
        dst += ( thisStringLen + 1 );
    }

    // final double-null
    *dst = '\000';

    FBuild::Get().SetEnvironmentString( envString.Get(), size, libEnvVar );
}
// Commit
//------------------------------------------------------------------------------
/*virtual*/ bool FunctionVCXProject::Commit( const BFFIterator & funcStartIter ) const
{
	// required
	AStackString<> projectOutput;
	AStackString<> rootNamespace;
	AStackString<> projectGuid;
	AStackString<> defaultLanguage;
	AStackString<> applicationEnvironment;
	if ( !GetString( funcStartIter, projectOutput,		".ProjectOutput", true ) ||
		 !GetString( funcStartIter, rootNamespace,		".RootNamespace", false ) ||
		 !GetString( funcStartIter, projectGuid,		".ProjectGuid", false ) ||
		 !GetString( funcStartIter, defaultLanguage,	".DefaultLanguage", false ) ||
		 !GetString( funcStartIter, applicationEnvironment,	".ApplicationEnvironment", false ) )
	{
		return false;
	}

	// optional inputs
	Array< AString > inputPaths;
	Array< AString > inputPathsExclude;
	if ( !GetStrings( funcStartIter, inputPaths,		".ProjectInputPaths", false ) ||
		 !GetStrings( funcStartIter, inputPathsExclude,	".ProjectInputPathsExclude", false ) )
	{
		return false;
	}

	// project base
	Array< AString > basePaths;
	if ( !GetStrings( funcStartIter, basePaths,	".ProjectBasePath", false ) )
	{
		return false;
	}
	CleanFolderPaths( basePaths );

	// references
	Array< AString > references;
	Array< AString > projectReferences;
	if ( !GetStrings( funcStartIter, references,		".ProjectReferences", false ) ||
		 !GetStrings( funcStartIter, projectReferences,	".ProjectProjectReferences", false ) )
	{
		return false;
	}

	// permitted file extensions
	Array< AString > allowedFileExtensions( 8, true );
	if ( !GetStrings( funcStartIter, allowedFileExtensions, ".ProjectAllowedFileExtensions", false ) )
	{
		return true;
	}
	if ( allowedFileExtensions.IsEmpty() )
	{
		const char * extensions[] = { ".cpp", ".hpp", ".cxx",".hxx",".c",".h",".cc",".hh",
									  ".cp",".hp",".cs",".inl",".bff",".rc",".resx",".m",".mm",
									  ".cu",
									  nullptr };
		AStackString<> tmp;
		const char ** item = extensions;
		while ( *item )
		{
			tmp.Assign( *item );
			allowedFileExtensions.Append( tmp );
			++item;
		}
	}

	// files and filesToExclude
	Array< AString > files( 8, true );
	Array< AString > filesToExclude( 8, true );	
	if ( !GetStrings( funcStartIter, files,				".ProjectFiles", false ) ||
 		 !GetStrings( funcStartIter, filesToExclude,	".ProjectFilesToExclude", false ) )
	{
		return false;
	}

	// filetypes
	Array< VSProjectFileType > fileTypes;
	const BFFVariable * projectFileTypes = BFFStackFrame::GetVar( ".ProjectFileTypes" );
	if ( projectFileTypes )
	{
		if ( projectFileTypes->IsArrayOfStructs() == false )
		{
			Error::Error_1050_PropertyMustBeOfType( funcStartIter, this, ".ProjectFileTypes", projectFileTypes->GetType(), BFFVariable::VAR_ARRAY_OF_STRUCTS );
			return false;
		}

		const Array< const BFFVariable * > & structs = projectFileTypes->GetArrayOfStructs();
		const BFFVariable * const * end = structs.End();
		for ( const BFFVariable ** it = structs.Begin(); it != end; ++it )
		{
			const BFFVariable * s = *it;

			VSProjectFileType ft;

			// .FileType must be provided
			if ( !GetStringFromStruct( s, ".FileType",	ft.m_FileType ) )
			{
				// TODO:B custom error
				Error::Error_1101_MissingProperty( funcStartIter, this, AStackString<>( ".FileType" ) );
				return false;
			}

			// .Pattern must be provided
			if ( !GetStringFromStruct( s, ".Pattern",	ft.m_Pattern ) )
			{
				// TODO:B custom error
				Error::Error_1101_MissingProperty( funcStartIter, this, AStackString<>( ".Pattern" ) );
				return false;
			}

			fileTypes.Append( ft );
		}
	}

	// path cleaning
	CleanFolderPaths( inputPaths );			// input paths
	CleanFolderPaths( inputPathsExclude );	// exclude paths
	CleanFilePaths( files );				// explicit files

	// per-config options
	VSProjectConfig baseConfig;

	// various options
	if ( !GetString( funcStartIter, baseConfig.m_BuildCommand,	".ProjectBuildCommand", false ) ||
		 !GetString( funcStartIter, baseConfig.m_RebuildCommand,".ProjectRebuildCommand", false ) ||
		 !GetString( funcStartIter, baseConfig.m_CleanCommand,	".ProjectCleanCommand", false ) ||
		 !GetString( funcStartIter, baseConfig.m_Output,		".Output", false ) ||
		 !GetString( funcStartIter, baseConfig.m_PreprocessorDefinitions,	".PreprocessorDefinitions", false ) ||
		 !GetString( funcStartIter, baseConfig.m_IncludeSearchPath,		".IncludeSearchPath", false ) ||
		 !GetString( funcStartIter, baseConfig.m_ForcedIncludes,		".ForcedIncludes", false ) ||
		 !GetString( funcStartIter, baseConfig.m_AssemblySearchPath,	".AssemblySearchPath", false ) ||
		 !GetString( funcStartIter, baseConfig.m_ForcedUsingAssemblies,	".ForcedUsingAssemblies", false ) ||
		 !GetString( funcStartIter, baseConfig.m_AdditionalOptions,		".AdditionalOptions", false ) ||
		 !GetString( funcStartIter, baseConfig.m_OutputDirectory,		".OutputDirectory", false ) ||
		 !GetString( funcStartIter, baseConfig.m_IntermediateDirectory,	".IntermediateDirectory", false ) ||
		 !GetString( funcStartIter, baseConfig.m_Xbox360DebuggerCommand,".Xbox360DebuggerCommand", false ) ||
		 !GetString( funcStartIter, baseConfig.m_LayoutDir,				".LayoutDir", false ) ||
		 !GetString( funcStartIter, baseConfig.m_LayoutExtensionFilter,	".LayoutExtensionFilter", false ) ||
		 !GetString( funcStartIter, baseConfig.m_DebuggerFlavor,		".DebuggerFlavor", false ) ||
		 !GetString( funcStartIter, baseConfig.m_AumidOverride,			".AumidOverride", false ) ||
		 !GetString( funcStartIter, baseConfig.m_PlatformToolset,		".PlatformToolset", false ) ||
		 !GetString( funcStartIter, baseConfig.m_DeploymentType,		".DeploymentType", false ) ||
		 !GetString( funcStartIter, baseConfig.m_DeploymentFiles,		".DeploymentFiles", false ) ||
		 !GetString( funcStartIter, baseConfig.m_LocalDebuggerCommandArguments,	".LocalDebuggerCommandArguments", false ) ||
		 !GetString( funcStartIter, baseConfig.m_LocalDebuggerWorkingDirectory,	".LocalDebuggerWorkingDirectory", false ) ||
		 !GetString( funcStartIter, baseConfig.m_LocalDebuggerCommand,			".LocalDebuggerCommand", false ) ||
		 !GetString( funcStartIter, baseConfig.m_LocalDebuggerEnvironment,		".LocalDebuggerEnvironment", false ) )
	{
		return false;
	}

	// create configs
	Array< VSProjectConfig > configs( 16, true );

	const BFFVariable * projectConfigs = BFFStackFrame::GetVar( ".ProjectConfigs" );
	if ( projectConfigs )
	{
		if ( projectConfigs->IsArrayOfStructs() == false )
		{
			Error::Error_1050_PropertyMustBeOfType( funcStartIter, this, ".ProjectConfigs", projectConfigs->GetType(), BFFVariable::VAR_ARRAY_OF_STRUCTS );
			return false;
		}

		const Array< const BFFVariable * > & structs = projectConfigs->GetArrayOfStructs();
		const BFFVariable * const * end = structs.End();
		for ( const BFFVariable ** it = structs.Begin(); it != end; ++it )
		{
			const BFFVariable * s = *it;

			// start with the base configuration
			VSProjectConfig newConfig( baseConfig );

			// .Platform must be provided
			if ( !GetStringFromStruct( s, ".Platform",	newConfig.m_Platform ) )
			{
				// TODO:B custom error
				Error::Error_1101_MissingProperty( funcStartIter, this, AStackString<>( ".Platform" ) );
				return false;
			}

			// .Config must be provided
			if ( !GetStringFromStruct( s, ".Config",	newConfig.m_Config ) )
			{
				// TODO:B custom error
				Error::Error_1101_MissingProperty( funcStartIter, this, AStackString<>( ".Config" ) );
				return false;
			}

			GetStringFromStruct( s, ".ProjectBuildCommand",		newConfig.m_BuildCommand );
			GetStringFromStruct( s, ".ProjectRebuildCommand",	newConfig.m_RebuildCommand );
			GetStringFromStruct( s, ".ProjectCleanCommand",		newConfig.m_CleanCommand );
			GetStringFromStruct( s, ".Output",					newConfig.m_Output );
			GetStringFromStruct( s, ".PreprocessorDefinitions",	newConfig.m_PreprocessorDefinitions );
			GetStringFromStruct( s, ".IncludeSearchPath",		newConfig.m_IncludeSearchPath );
			GetStringFromStruct( s, ".ForcedIncludes",			newConfig.m_ForcedIncludes );
			GetStringFromStruct( s, ".AssemblySearchPath",		newConfig.m_AssemblySearchPath );
			GetStringFromStruct( s, ".ForcedUsingAssemblies",	newConfig.m_ForcedUsingAssemblies );
			GetStringFromStruct( s, ".AdditionalOptions",		newConfig.m_AdditionalOptions );
			GetStringFromStruct( s, ".OutputDirectory",			newConfig.m_OutputDirectory );
			GetStringFromStruct( s, ".IntermediateDirectory",	newConfig.m_IntermediateDirectory );
		 	GetStringFromStruct( s, ".LayoutDir",				newConfig.m_LayoutDir );
			GetStringFromStruct( s, ".LayoutExtensionFilter",	newConfig.m_LayoutExtensionFilter );
			GetStringFromStruct( s, ".Xbox360DebuggerCommand",	newConfig.m_Xbox360DebuggerCommand );
			GetStringFromStruct( s, ".DebuggerFlavor",			newConfig.m_DebuggerFlavor );
			GetStringFromStruct( s, ".AumidOverride",			newConfig.m_AumidOverride );
			GetStringFromStruct( s, ".PlatformToolset",			newConfig.m_PlatformToolset );
			GetStringFromStruct( s, ".DeploymentType",			newConfig.m_DeploymentType );
			GetStringFromStruct( s, ".DeploymentFiles",			newConfig.m_DeploymentFiles );
			GetStringFromStruct( s, ".LocalDebuggerCommandArguments",	newConfig.m_LocalDebuggerCommandArguments );
			GetStringFromStruct( s, ".LocalDebuggerWorkingDirectory",	newConfig.m_LocalDebuggerWorkingDirectory );
			GetStringFromStruct( s, ".LocalDebuggerCommand",			newConfig.m_LocalDebuggerCommand );
			GetStringFromStruct( s, ".LocalDebuggerEnvironment",		newConfig.m_LocalDebuggerEnvironment );

			configs.Append( newConfig );
		}
	}
	else
	{
		// no user specified configs, make some defaults

		// start from the default
		VSProjectConfig config( baseConfig );

		// make the configs
		config.m_Platform	= "Win32";
		config.m_Config		= "Debug";
		configs.Append( config );
		config.m_Config		= "Release";
		configs.Append( config );
		config.m_Platform	= "x64";
		configs.Append( config );
		config.m_Config		= "Debug";
		configs.Append( config );
	}

	NodeGraph & ng = FBuild::Get().GetDependencyGraph();

	// create all of the DirectoryListNodes we need
	Dependencies dirNodes( inputPaths.GetSize() );
	if ( !GetDirectoryListNodeList( funcStartIter, inputPaths, Array< AString >(), Array< AString >(), true, nullptr, "ProjectInputPaths", dirNodes ) )
	{
		return false; // GetDirectoryListNodeList will have emitted an error
	}

	// Check for existing node
	if ( ng.FindNode( projectOutput ) )
	{
		Error::Error_1100_AlreadyDefined( funcStartIter, this, projectOutput );
		return false;
	}

	VCXProjectNode * pn = ng.CreateVCXProjectNode( projectOutput,
												   basePaths,
												   dirNodes,
												   inputPathsExclude, // TODO:B Remove this (handled by DirectoryListNode now)
												   allowedFileExtensions, // TODO:B Remove this (handled by DirectoryListNode now)
												   files,
												   filesToExclude,
												   rootNamespace,
												   projectGuid,
												   defaultLanguage,
												   applicationEnvironment,
												   configs,
												   fileTypes,
												   references,
												   projectReferences );

	ASSERT( pn );

	return ProcessAlias( funcStartIter, pn );
}
Example #3
0
// CreateDynamicObjectNode
//------------------------------------------------------------------------------
bool ObjectListNode::CreateDynamicObjectNode( NodeGraph & nodeGraph, Node * inputFile, const AString & baseDir, bool isUnityNode, bool isIsolatedFromUnityNode )
{
    const AString & fileName = inputFile->GetName();

    // Transform src file to dst object path
    // get file name only (no path, no ext)
    const char * lastSlash = fileName.FindLast( NATIVE_SLASH );
    lastSlash = lastSlash ? ( lastSlash + 1 ) : fileName.Get();
    const char * lastDot = fileName.FindLast( '.' );
    lastDot = lastDot && ( lastDot > lastSlash ) ? lastDot : fileName.GetEnd();

    // if source comes from a directory listing, use path relative to dirlist base
    // to replicate the folder hierearchy in the output
    AStackString<> subPath;
    if ( baseDir.IsEmpty() == false )
    {
        ASSERT( NodeGraph::IsCleanPath( baseDir ) );
        if ( PathUtils::PathBeginsWith( fileName, baseDir ) )
        {
            // ... use everything after that
            subPath.Assign( fileName.Get() + baseDir.GetLength(), lastSlash ); // includes last slash
        }
    }
    else
    {
        if ( !m_BaseDirectory.IsEmpty() && PathUtils::PathBeginsWith( fileName, m_BaseDirectory ) )
        {
            // ... use everything after that
            subPath.Assign( fileName.Get() + m_BaseDirectory.GetLength(), lastSlash ); // includes last slash
        }
    }

    AStackString<> fileNameOnly( lastSlash, lastDot );
    AStackString<> objFile( m_CompilerOutputPath );
    objFile += subPath;
    objFile += m_CompilerOutputPrefix;
    objFile += fileNameOnly;
    objFile += GetObjExtension();

    // Create an ObjectNode to compile the above file
    // and depend on that
    Node * on = nodeGraph.FindNode( objFile );
    if ( on == nullptr )
    {
        // determine flags - TODO:B Move DetermineFlags call out of build-time
        const bool usingPCH = ( m_PrecompiledHeader != nullptr );
        uint32_t flags = ObjectNode::DetermineFlags( m_Compiler, m_CompilerArgs, false, usingPCH );
        if ( isUnityNode )
        {
            flags |= ObjectNode::FLAG_UNITY;
        }
        if ( isIsolatedFromUnityNode )
        {
            flags |= ObjectNode::FLAG_ISOLATED_FROM_UNITY;
        }
        uint32_t preprocessorFlags = 0;
        if ( m_Preprocessor )
        {
            // determine flags - TODO:B Move DetermineFlags call out of build-time
            preprocessorFlags = ObjectNode::DetermineFlags( m_Preprocessor, m_PreprocessorArgs, false, usingPCH );
        }

        on = nodeGraph.CreateObjectNode( objFile, inputFile, m_Compiler, m_CompilerArgs, m_CompilerArgsDeoptimized, m_PrecompiledHeader, flags, m_CompilerForceUsing, m_DeoptimizeWritableFiles, m_DeoptimizeWritableFilesWithToken, m_AllowDistribution, m_AllowCaching, m_Preprocessor, m_PreprocessorArgs, preprocessorFlags );
    }
    else if ( on->GetType() != Node::OBJECT_NODE )
    {
        FLOG_ERROR( "Node '%s' is not an ObjectNode (type: %s)", on->GetName().Get(), on->GetTypeName() );
        return false;
    }
    else
    {
        ObjectNode * other = on->CastTo< ObjectNode >();
        if ( inputFile != other->GetSourceFile() )
        {
            FLOG_ERROR( "Conflicting objects found:\n"
                        " File A: %s\n"
                        " File B: %s\n"
                        " Both compile to: %s\n",
                        inputFile->GetName().Get(),
                        other->GetSourceFile()->GetName().Get(),
                        objFile.Get() );
            return false;
        }
    }
    m_DynamicDependencies.Append( Dependency( on ) );
    return true;
}
Example #4
0
// ParseIncludeDirective
//------------------------------------------------------------------------------
bool BFFParser::ParseIncludeDirective( BFFIterator & iter )
{
	// Sanity check include depth to detect cyclic includes
	if ( s_Depth >= 128 )
	{
		Error::Error_1035_ExcessiveDepthComplexity( iter );
		return false;
	}

	// we expect a " quoted string
	if ( *iter != '"' )
	{
		Error::Error_1031_UnexpectedCharFollowingDirectiveName( iter, AStackString<>( "include" ), '"' ); 
		return false;
	}

	BFFIterator stringStart( iter );
	stringStart++; // first actual character

	// find end of string
	if ( iter.ParseToNext( '"' ) == false )
	{
		Error::Error_1012_UnexpectedEndOfFile( iter );
		return false;
	}

	// unescape and substitute variables
	AStackString<> include;
	if ( PerformVariableSubstitutions( stringStart, iter, include ) == false )
	{
		return false;
	}

	iter++; // skip closing quote before returning

	FLOG_INFO( "Including: %s\n", include.Get() );

	// open include

	// 1) Try current directory
	AStackString<> includeToUse;
	if (PathUtils::IsFullPath(include) == false)
	{
		const char * lastSlash = iter.GetFileName().FindLast( NATIVE_SLASH );
		lastSlash = lastSlash ? lastSlash : iter.GetFileName().FindLast( OTHER_SLASH );
		lastSlash = lastSlash ? ( lastSlash + 1 ): iter.GetFileName().Get(); // file only, truncate to empty
		includeToUse.Assign( iter.GetFileName().Get(), lastSlash );
	}
	includeToUse += include;
	AStackString<> includeToUseClean;
	NodeGraph::CleanPath( includeToUse, includeToUseClean );
	FileStream f;
	if ( f.Open( includeToUseClean.Get(), FileStream::READ_ONLY ) == false )
	{
		Error::Error_1032_UnableToOpenInclude( stringStart, includeToUseClean );
		return false;
	}

	// check if include uses "once" pragma
	if ( FBuild::Get().GetDependencyGraph().IsOneUseFile( includeToUseClean ) )
	{
		// already seen, and uses #once : don't include again
		return true;
	}

	uint64_t includeTimeStamp = FileIO::GetFileLastWriteTime( includeToUseClean );

	// read content of include
	const uint32_t fileSize = (uint32_t)f.GetFileSize();
	AutoPtr< char > mem( (char *)ALLOC( fileSize + 1 ) );
	if ( f.Read( mem.Get(), fileSize ) != fileSize )
	{
		Error::Error_1033_ErrorReadingInclude( stringStart, include, Env::GetLastErr() );
		return false;
	}
	mem.Get()[ fileSize ] = '\000'; // sentinel
	BFFParser parser;
	const bool pushStackFrame = false; // include is treated as if injected at this point
	return parser.Parse( mem.Get(), fileSize, includeToUseClean.Get(), includeTimeStamp, pushStackFrame ); 
}
Example #5
0
// BuildArgs
//------------------------------------------------------------------------------
bool LibraryNode::BuildArgs( Args & fullArgs ) const
{
	Array< AString > tokens( 1024, true );
	m_LibrarianArgs.Tokenize( tokens );

	const AString * const end = tokens.End();
	for ( const AString * it = tokens.Begin(); it!=end; ++it )
	{
		const AString & token = *it;
		if ( token.EndsWith( "%1" ) )
		{
			// handle /Option:%1 -> /Option:A /Option:B /Option:C
			AStackString<> pre;
			if ( token.GetLength() > 2 )
			{
				pre.Assign( token.Get(), token.GetEnd() - 2 );
			}

			// concatenate files, unquoted
			GetInputFiles( fullArgs, pre, AString::GetEmpty() );
		}
		else if ( token.EndsWith( "\"%1\"" ) )
		{
			// handle /Option:"%1" -> /Option:"A" /Option:"B" /Option:"C"
			AStackString<> pre( token.Get(), token.GetEnd() - 3 ); // 3 instead of 4 to include quote
			AStackString<> post( "\"" );

			// concatenate files, quoted
			GetInputFiles( fullArgs, pre, post );
		}
		else if ( token.EndsWith( "%2" ) )
		{
			// handle /Option:%2 -> /Option:A
			if ( token.GetLength() > 2 )
			{
				fullArgs += AStackString<>( token.Get(), token.GetEnd() - 2 );
			}
			fullArgs += m_Name;
		}
		else if ( token.EndsWith( "\"%2\"" ) )
		{
			// handle /Option:"%2" -> /Option:"A"
			AStackString<> pre( token.Get(), token.GetEnd() - 3 ); // 3 instead of 4 to include quote
			fullArgs += pre;
			fullArgs += m_Name;
			fullArgs += '"'; // post
		}
		else
		{
			fullArgs += token;
		}

		fullArgs.AddDelimiter();
	}

	// orbis-ar.exe requires escaped slashes inside response file
	if ( GetFlag( LIB_FLAG_ORBIS_AR ) )
	{
		fullArgs.SetEscapeSlashesInResponseFile();
	}

	// Handle all the special needs of args
	if ( fullArgs.Finalize( m_LibrarianPath, GetName(), CanUseResponseFile() ) == false )
	{
		return false; // Finalize will have emitted an error
	}

	return true;
}
// ExtractIntellisenseOptions
//------------------------------------------------------------------------------
/*static*/ void ProjectGeneratorBase::ExtractIntellisenseOptions( const AString & compilerArgs,
                                                                  const char * option,
                                                                  const char * alternateOption,
                                                                  Array< AString > & outOptions,
                                                                  bool escapeQuotes )
{
    ASSERT( option );
    Array< AString > tokens;
    compilerArgs.Tokenize( tokens );

    const size_t optionLen = AString::StrLen( option );
    const size_t alternateOptionLen = alternateOption ? AString::StrLen( alternateOption ) : 0;

    for ( size_t i=0; i<tokens.GetSize(); ++i )
    {
        AString & token = tokens[ i ];

        // strip quotes around token, e.g:    "-IFolder/Folder"
        if ( token.BeginsWith( '"' ) && token.EndsWith( '"' ) )
        {
            token.Assign( token.Get() + 1, token.GetEnd() - 1 );
        }

        AStackString<> optionBody;

        // Handle space between option and payload
        if ( ( token == option ) || ( token == alternateOption ) )
        {
            // Handle an incomplete token at the end of list
            if ( i == ( tokens.GetSize() - 1 ) )
            {
                break;
            }

            // Use next token
            optionBody = tokens[ i + 1 ];
        }
        else if ( token.BeginsWith( option ) )
        {
            // use everything after token
            optionBody.Assign( token.Get() + optionLen );
        }
        else if ( alternateOption && token.BeginsWith( alternateOption ) )
        {
            // use everything after token
            optionBody.Assign( token.Get() + alternateOptionLen );
        }

        // Strip quotes around body (e.g. -I"Folder/Folder")
        if ( optionBody.BeginsWith( '"' ) && optionBody.EndsWith( '"' ) )
        {
            optionBody.Trim( 1, 1 );
        }

        // Did we find something?
        if ( optionBody.IsEmpty() == false )
        {
            if ( escapeQuotes )
            {
                optionBody.Replace( "\"", "\\\"" );
            }
            outOptions.Append( optionBody );
        }
    }
}
Example #7
0
// BuildArgs
//------------------------------------------------------------------------------
bool CSNode::BuildArgs( Args & fullArgs ) const
{
	// split into tokens
	Array< AString > tokens( 1024, true );
	m_CompilerArgs.Tokenize( tokens );

	AStackString<> quote( "\"" );

	const AString * const end = tokens.End();
	for ( const AString * it = tokens.Begin(); it!=end; ++it )
	{
		const AString & token = *it;
		if ( token.EndsWith( "%1" ) )
		{
			// handle /Option:%1 -> /Option:A /Option:B /Option:C
			AStackString<> pre;
			if ( token.GetLength() > 2 )
			{
				pre.Assign( token.Get(), token.GetEnd() - 2 );
			}

			// concatenate files, unquoted
			GetInputFiles( fullArgs, pre, AString::GetEmpty() );
		}
		else if ( token.EndsWith( "\"%1\"" ) )
		{
			// handle /Option:"%1" -> /Option:"A" /Option:"B" /Option:"C"
			AStackString<> pre( token.Get(), token.GetEnd() - 3 ); // 3 instead of 4 to include quote

			// concatenate files, quoted
			GetInputFiles( fullArgs, pre, quote );
		}
		else if ( token.EndsWith( "%2" ) )
		{
			// handle /Option:%2 -> /Option:A
			if ( token.GetLength() > 2 )
			{
				fullArgs += AStackString<>( token.Get(), token.GetEnd() - 2 );
			}
			fullArgs += m_Name;
		}
		else if ( token.EndsWith( "\"%2\"" ) )
		{
			// handle /Option:"%2" -> /Option:"A"
			AStackString<> pre( token.Get(), token.GetEnd() - 3 ); // 3 instead of 4 to include quote
			fullArgs += pre;
			fullArgs += m_Name;
			fullArgs += '"'; // post
		}
		else if ( token.EndsWith( "%3" ) )
		{
			// handle /Option:%3 -> /Option:A,B,C
			AStackString<> pre( token.Get(), token.GetEnd() - 2 );
			fullArgs += pre;

			// concatenate files, unquoted
			GetExtraRefs( fullArgs, AString::GetEmpty(), AString::GetEmpty() );
		}
		else if ( token.EndsWith( "\"%3\"" ) )
		{
			// handle /Option:"%3" -> /Option:"A","B","C"
			AStackString<> pre( token.Get(), token.GetEnd() - 4 );
			fullArgs += pre;

			// concatenate files, quoted
			GetExtraRefs( fullArgs, quote, quote );
		}
		else
		{
			fullArgs += token;
		}

		fullArgs.AddDelimiter();
	}

	// Handle all the special needs of args
	const bool canUseResponseFile( true );
	if ( fullArgs.Finalize( m_CompilerPath, GetName(), canUseResponseFile ) == false )
	{
		return false; // Finalize will have emitted an error
	}

	return true;
}