|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1989 - 1994.
//
// File: buildinc.c
//
// Contents: This is the checking include module for the NT Build Tool (BUILD.EXE)
//
// Used for detecting the includes that do not satisfy the acceptable
// patterns.
//
// History: see SLM
//----------------------------------------------------------------------------
#include "build.h"
//+---------------------------------------------------------------------------
//
// Function: FoundCountedSequenceInString
//
// Synopsis: Roughly equivalent to "strstr" except that the substring doesn't
// have to be NULL-terminated.
//
// Arguments: [String] -- null-terminated string to search
// [Sequence] -- string to search for
// [Length] -- the length of the sequence
//----------------------------------------------------------------------------
LPCTSTR FindCountedSequenceInString( IN LPCTSTR String, IN LPCTSTR Sequence, IN DWORD Length ) {
assert( Sequence ); assert( String );
if ( Length > 0 ) {
while ( *String ) {
while (( *String ) && ( *String != *Sequence )) { String++; }
if ( *String ) {
LPCTSTR SubString = String + 1; LPCTSTR SubSequence = Sequence + 1; DWORD Remaining = Length - 1;
while (( Remaining ) && ( *SubString++ == *SubSequence++ )) { Remaining--; }
if ( Remaining == 0 ) { return String; }
String++; } }
return NULL; }
return String; }
//+---------------------------------------------------------------------------
//
// Function: DoesInstanceMatchPattern
//
// Synopsis: Returns TRUE if pattern matches instance.
// Wildcards:
// * matches any text
// ? matches any and exactly one character
// # matches any text up to backslash character or end of string
//
// Arguments: [Instance] -- the string to be matched
// [Pattern] -- the pattern
//----------------------------------------------------------------------------
BOOL DoesInstanceMatchPattern( IN LPCTSTR Instance, IN LPCTSTR Pattern ) {
assert( Instance ); assert( Pattern );
while ( *Pattern ) {
if ( *Pattern == TEXT('*')) {
Pattern++;
while ( *Pattern == TEXT('*')) { // skip multiple '*' characters
Pattern++; }
if ( *Pattern == 0 ) { // '*' at end of pattern matches rest
return TRUE; }
if ( *Pattern == '?' ) { // '?' following '*'
//
// Expensive because we have to restart match for every
// character position remaining since '?' can match anything.
//
while ( *Instance ) {
if ( DoesInstanceMatchPattern( Instance, Pattern )) { return TRUE; }
Instance++; }
return FALSE; }
else {
//
// Now we know that next character in pattern is a regular
// character to be matched. Find out the length of that
// string to the next wildcard or end of string.
//
LPCTSTR NextWildCard = Pattern + 1; DWORD MatchLength;
while (( *NextWildCard ) && ( *NextWildCard != TEXT('*')) && ( *NextWildCard != TEXT('?')) && ( *NextWildCard != TEXT('#'))) { NextWildCard++; }
MatchLength = (DWORD)(NextWildCard - Pattern); // always non-zero
//
// Now try to match with any instance of substring in pattern
// found in the instance.
//
Instance = FindCountedSequenceInString( Instance, Pattern, MatchLength );
while ( Instance ) {
if ( DoesInstanceMatchPattern( Instance + MatchLength, NextWildCard )) { return TRUE; }
Instance = FindCountedSequenceInString( Instance + 1, Pattern, MatchLength ); }
return FALSE; } }
else if ( *Pattern == TEXT('#')) {
//
// Match text up to backslash character or end of string
//
Pattern++;
while (( *Instance != 0 ) && ( *Instance != '\\' )) { Instance++; }
continue; }
else if ( *Pattern == TEXT('?')) {
if ( *Instance == 0 ) { return FALSE; } }
else if ( *Pattern != *Instance ) {
return FALSE; }
Pattern++; Instance++; }
return ( *Instance == 0 ); }
//+---------------------------------------------------------------------------
//
// Function: CombinePaths
//
// Synopsis: Combine two strings to get a full path.
//
// Arguments: [ParentPath] -- head path
// [ChildPath] -- path to be added
// [TargetPath] -- full path
//----------------------------------------------------------------------------
LPSTR CombinePaths( IN LPCSTR ParentPath, IN LPCSTR ChildPath, OUT LPSTR TargetPath // can be same as ParentPath if want to append
) {
ULONG ParentLength = strlen( ParentPath ); LPSTR p;
assert( ParentPath ); assert( ChildPath );
if ( ParentPath != TargetPath ) { memcpy( TargetPath, ParentPath, ParentLength ); }
p = TargetPath + ParentLength;
if (( ParentLength > 0 ) && ( *( p - 1 ) != '\\' ) && ( *( p - 1 ) != '/' )) { *p++ = '\\'; }
strcpy( p, ChildPath );
return TargetPath; }
//+---------------------------------------------------------------------------
//
// Function: CreateRelativePath
//
// Synopsis: Determine the "canonical" path of one file relative to
// another file
//
// Arguments: [SourceAbsName] -- absolute path of the source file
// [TargetAbsName] -- absolute path of the target file
// [RelativePath] -- resulted relative path
//----------------------------------------------------------------------------
VOID CreateRelativePath( IN LPCSTR SourceAbsName, // must be lowercase
IN LPCSTR TargetAbsName, // must be lowercase
OUT LPSTR RelativePath // must be large enough
) {
//
// First, walk through path components that match in Source and Target.
// For example:
//
// d:\nt\private\ntos\dd\efs.h
// d:\nt\private\windows\base\ntcrypto\des.h
// ^
// This is where the relative path stops going up (..)
// and starts going back down.
//
// So, the "cannonical" relative path generated should look like:
//
// ..\..\..\windows\base\ntcrypto\des.h
//
// For relative includes that are "below" the includer in the path should
// look like this:
//
// .\foo\bar\foobar.h
//
LPCSTR Source = SourceAbsName; LPCSTR Target = TargetAbsName; LPSTR Output = RelativePath; ULONG PathSeparatorIndex; BOOL AnyParent; ULONG i;
assert( SourceAbsName ); assert( TargetAbsName );
PathSeparatorIndex = 0;
i = 0;
//
// Scan forward to first non-matching character, and keep track of
// most recent path separator character.
//
while (( Source[ i ] == Target[ i ] ) && ( Source[ i ] != 0 )) {
if ( Source[ i ] == '\\' ) { PathSeparatorIndex = i; }
++i; }
//
// Coming out of this loop, there are 2 possibilities:
//
// 1) Found common ancestor path ( *PathSeparatorIndex == '\\' )
// 2) Don't have common ancestor ( *PathSeparatorIndex != '\\' )
//
if ( Source[ PathSeparatorIndex ] != '\\' ) { strcpy( RelativePath, TargetAbsName ); return; }
i = PathSeparatorIndex + 1;
//
// Now continue to walk down source path and insert a "..\" in the result
// for each path separator encountered.
//
AnyParent = FALSE;
while ( Source[ i ] != 0 ) {
if ( Source[ i ] == '\\' ) {
AnyParent = TRUE; *Output++ = '.'; *Output++ = '.'; *Output++ = '\\'; }
++i; }
if ( ! AnyParent ) {
//
// Relative path is below current directory.
//
*Output++ = '.'; *Output++ = '\\'; }
//
// Now we simply append what's remaining of the Target path from the
// ancestor match point.
//
strcpy( Output, Target + PathSeparatorIndex + 1 ); }
//+---------------------------------------------------------------------------
//
// Function: ShouldWarnInclude
//
// Synopsis: Returns true if the name of the included file matches a
// BUILD_UNACCEPTABLE_INCLUDES pattern or it does not match
// any of the patterns specified in BUILD_ACCEPTABLE_INCLUDES.
//
// Arguments: [CompilandFullName] -- name of the including file
// [IncludeeFullName] -- name of the included file
//----------------------------------------------------------------------------
BOOL ShouldWarnInclude( IN LPCSTR CompilandFullName, IN LPCSTR IncludeeFullName ) { UINT i; CHAR IncludeeRelativeName[ MAX_PATH ];
assert( CompilandFullName ); assert( IncludeeFullName );
CreateRelativePath( CompilandFullName, IncludeeFullName, IncludeeRelativeName );
//
// First we check for a match against any unacceptable include path
// because we always want to warn about these.
//
for ( i = 0; UnacceptableIncludePatternList[ i ] != NULL; i++ ) {
if ( DoesInstanceMatchPattern( IncludeeFullName, UnacceptableIncludePatternList[ i ] )) { return TRUE; }
if ( DoesInstanceMatchPattern( IncludeeRelativeName, UnacceptableIncludePatternList[ i ] )) { return TRUE; } }
//
// If we get to here, the include path was not explicitly unacceptable, so
// we now want to see if it matches any acceptable paths. But, if no
// acceptable paths are specified, we don't want to warn.
//
if ( AcceptableIncludePatternList[ 0 ] == NULL ) { return FALSE; }
for ( i = 0; AcceptableIncludePatternList[ i ] != NULL; i++ ) {
if ( DoesInstanceMatchPattern( IncludeeFullName, AcceptableIncludePatternList[ i ] )) { return FALSE; }
if ( DoesInstanceMatchPattern( IncludeeRelativeName, AcceptableIncludePatternList[ i ] )) { return FALSE; } }
return TRUE; }
//+---------------------------------------------------------------------------
//
// Function: CheckIncludeForWarning
//
// Synopsis: Warnings if the dependency does not respect the
// BUILD_UNACCEPTABLE_INCLUDES or BUILD_ACCEPTABLE_INCLUDES
// restristions. Works with build -#.
//
// Arguments: [CompilandDir]
// [CompilandName]
// [IncluderDir]
// [IncluderName]
// [IncludeeDir]
// [IncludeeName]
//----------------------------------------------------------------------------
VOID CheckIncludeForWarning( IN LPCSTR CompilandDir, IN LPCSTR CompilandName, IN LPCSTR IncluderDir, IN LPCSTR IncluderName, IN LPCSTR IncludeeDir, IN LPCSTR IncludeeName ) {
CHAR CompilandFullName[ MAX_PATH ]; CHAR IncluderFullName[ MAX_PATH ]; CHAR IncludeeFullName[ MAX_PATH ];
assert( CompilandDir ); assert( CompilandName ); assert( IncluderDir ); assert( IncluderName ); assert( IncludeeDir ); assert( IncludeeName );
CombinePaths( CompilandDir, CompilandName, CompilandFullName ); CombinePaths( IncluderDir, IncluderName, IncluderFullName ); CombinePaths( IncludeeDir, IncludeeName, IncludeeFullName );
_strlwr( CompilandFullName ); _strlwr( IncluderFullName ); _strlwr( IncludeeFullName );
if ( IncFile ) { fprintf( IncFile, "%s includes %s\r\n", IncluderFullName, IncludeeFullName ); }
if ( ShouldWarnInclude( CompilandFullName, IncludeeFullName )) {
if ( strcmp( IncluderFullName, CompilandFullName ) == 0 ) {
if ( WrnFile ) {
fprintf( WrnFile, "WARNING: %s includes %s\n", CompilandFullName, IncludeeFullName ); }
if ( fShowWarningsOnScreen ) {
BuildMsgRaw( "WARNING: %s includes %s\n", CompilandFullName, IncludeeFullName ); } }
else {
if ( WrnFile ) {
fprintf( WrnFile, "WARNING: %s includes %s through %s\n", CompilandFullName, IncludeeFullName, IncluderFullName ); }
if ( fShowWarningsOnScreen ) {
BuildMsgRaw( "WARNING: %s includes %s through %s\n", CompilandFullName, IncludeeFullName, IncluderFullName ); } } } }
|