Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

540 lines
15 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1989 - 1994.
  5. //
  6. // File: buildinc.c
  7. //
  8. // Contents: This is the checking include module for the NT Build Tool (BUILD.EXE)
  9. //
  10. // Used for detecting the includes that do not satisfy the acceptable
  11. // patterns.
  12. //
  13. // History: see SLM
  14. //----------------------------------------------------------------------------
  15. #include "build.h"
  16. //+---------------------------------------------------------------------------
  17. //
  18. // Function: FoundCountedSequenceInString
  19. //
  20. // Synopsis: Roughly equivalent to "strstr" except that the substring doesn't
  21. // have to be NULL-terminated.
  22. //
  23. // Arguments: [String] -- null-terminated string to search
  24. // [Sequence] -- string to search for
  25. // [Length] -- the length of the sequence
  26. //----------------------------------------------------------------------------
  27. LPCTSTR
  28. FindCountedSequenceInString(
  29. IN LPCTSTR String,
  30. IN LPCTSTR Sequence,
  31. IN DWORD Length
  32. )
  33. {
  34. assert( Sequence );
  35. assert( String );
  36. if ( Length > 0 ) {
  37. while ( *String ) {
  38. while (( *String ) && ( *String != *Sequence )) {
  39. String++;
  40. }
  41. if ( *String ) {
  42. LPCTSTR SubString = String + 1;
  43. LPCTSTR SubSequence = Sequence + 1;
  44. DWORD Remaining = Length - 1;
  45. while (( Remaining ) && ( *SubString++ == *SubSequence++ )) {
  46. Remaining--;
  47. }
  48. if ( Remaining == 0 ) {
  49. return String;
  50. }
  51. String++;
  52. }
  53. }
  54. return NULL;
  55. }
  56. return String;
  57. }
  58. //+---------------------------------------------------------------------------
  59. //
  60. // Function: DoesInstanceMatchPattern
  61. //
  62. // Synopsis: Returns TRUE if pattern matches instance.
  63. // Wildcards:
  64. // * matches any text
  65. // ? matches any and exactly one character
  66. // # matches any text up to backslash character or end of string
  67. //
  68. // Arguments: [Instance] -- the string to be matched
  69. // [Pattern] -- the pattern
  70. //----------------------------------------------------------------------------
  71. BOOL
  72. DoesInstanceMatchPattern(
  73. IN LPCTSTR Instance,
  74. IN LPCTSTR Pattern
  75. )
  76. {
  77. assert( Instance );
  78. assert( Pattern );
  79. while ( *Pattern ) {
  80. if ( *Pattern == TEXT('*')) {
  81. Pattern++;
  82. while ( *Pattern == TEXT('*')) { // skip multiple '*' characters
  83. Pattern++;
  84. }
  85. if ( *Pattern == 0 ) { // '*' at end of pattern matches rest
  86. return TRUE;
  87. }
  88. if ( *Pattern == '?' ) { // '?' following '*'
  89. //
  90. // Expensive because we have to restart match for every
  91. // character position remaining since '?' can match anything.
  92. //
  93. while ( *Instance ) {
  94. if ( DoesInstanceMatchPattern( Instance, Pattern )) {
  95. return TRUE;
  96. }
  97. Instance++;
  98. }
  99. return FALSE;
  100. }
  101. else {
  102. //
  103. // Now we know that next character in pattern is a regular
  104. // character to be matched. Find out the length of that
  105. // string to the next wildcard or end of string.
  106. //
  107. LPCTSTR NextWildCard = Pattern + 1;
  108. DWORD MatchLength;
  109. while (( *NextWildCard ) && ( *NextWildCard != TEXT('*')) && ( *NextWildCard != TEXT('?')) && ( *NextWildCard != TEXT('#'))) {
  110. NextWildCard++;
  111. }
  112. MatchLength = (DWORD)(NextWildCard - Pattern); // always non-zero
  113. //
  114. // Now try to match with any instance of substring in pattern
  115. // found in the instance.
  116. //
  117. Instance = FindCountedSequenceInString( Instance, Pattern, MatchLength );
  118. while ( Instance ) {
  119. if ( DoesInstanceMatchPattern( Instance + MatchLength, NextWildCard )) {
  120. return TRUE;
  121. }
  122. Instance = FindCountedSequenceInString( Instance + 1, Pattern, MatchLength );
  123. }
  124. return FALSE;
  125. }
  126. }
  127. else if ( *Pattern == TEXT('#')) {
  128. //
  129. // Match text up to backslash character or end of string
  130. //
  131. Pattern++;
  132. while (( *Instance != 0 ) && ( *Instance != '\\' )) {
  133. Instance++;
  134. }
  135. continue;
  136. }
  137. else if ( *Pattern == TEXT('?')) {
  138. if ( *Instance == 0 ) {
  139. return FALSE;
  140. }
  141. }
  142. else if ( *Pattern != *Instance ) {
  143. return FALSE;
  144. }
  145. Pattern++;
  146. Instance++;
  147. }
  148. return ( *Instance == 0 );
  149. }
  150. //+---------------------------------------------------------------------------
  151. //
  152. // Function: CombinePaths
  153. //
  154. // Synopsis: Combine two strings to get a full path.
  155. //
  156. // Arguments: [ParentPath] -- head path
  157. // [ChildPath] -- path to be added
  158. // [TargetPath] -- full path
  159. //----------------------------------------------------------------------------
  160. LPSTR
  161. CombinePaths(
  162. IN LPCSTR ParentPath,
  163. IN LPCSTR ChildPath,
  164. OUT LPSTR TargetPath // can be same as ParentPath if want to append
  165. )
  166. {
  167. ULONG ParentLength = strlen( ParentPath );
  168. LPSTR p;
  169. assert( ParentPath );
  170. assert( ChildPath );
  171. if ( ParentPath != TargetPath ) {
  172. memcpy( TargetPath, ParentPath, ParentLength );
  173. }
  174. p = TargetPath + ParentLength;
  175. if (( ParentLength > 0 ) &&
  176. ( *( p - 1 ) != '\\' ) &&
  177. ( *( p - 1 ) != '/' )) {
  178. *p++ = '\\';
  179. }
  180. strcpy( p, ChildPath );
  181. return TargetPath;
  182. }
  183. //+---------------------------------------------------------------------------
  184. //
  185. // Function: CreateRelativePath
  186. //
  187. // Synopsis: Determine the "canonical" path of one file relative to
  188. // another file
  189. //
  190. // Arguments: [SourceAbsName] -- absolute path of the source file
  191. // [TargetAbsName] -- absolute path of the target file
  192. // [RelativePath] -- resulted relative path
  193. //----------------------------------------------------------------------------
  194. VOID
  195. CreateRelativePath(
  196. IN LPCSTR SourceAbsName, // must be lowercase
  197. IN LPCSTR TargetAbsName, // must be lowercase
  198. OUT LPSTR RelativePath // must be large enough
  199. )
  200. {
  201. //
  202. // First, walk through path components that match in Source and Target.
  203. // For example:
  204. //
  205. // d:\nt\private\ntos\dd\efs.h
  206. // d:\nt\private\windows\base\ntcrypto\des.h
  207. // ^
  208. // This is where the relative path stops going up (..)
  209. // and starts going back down.
  210. //
  211. // So, the "cannonical" relative path generated should look like:
  212. //
  213. // ..\..\..\windows\base\ntcrypto\des.h
  214. //
  215. // For relative includes that are "below" the includer in the path should
  216. // look like this:
  217. //
  218. // .\foo\bar\foobar.h
  219. //
  220. LPCSTR Source = SourceAbsName;
  221. LPCSTR Target = TargetAbsName;
  222. LPSTR Output = RelativePath;
  223. ULONG PathSeparatorIndex;
  224. BOOL AnyParent;
  225. ULONG i;
  226. assert( SourceAbsName );
  227. assert( TargetAbsName );
  228. PathSeparatorIndex = 0;
  229. i = 0;
  230. //
  231. // Scan forward to first non-matching character, and keep track of
  232. // most recent path separator character.
  233. //
  234. while (( Source[ i ] == Target[ i ] ) && ( Source[ i ] != 0 )) {
  235. if ( Source[ i ] == '\\' ) {
  236. PathSeparatorIndex = i;
  237. }
  238. ++i;
  239. }
  240. //
  241. // Coming out of this loop, there are 2 possibilities:
  242. //
  243. // 1) Found common ancestor path ( *PathSeparatorIndex == '\\' )
  244. // 2) Don't have common ancestor ( *PathSeparatorIndex != '\\' )
  245. //
  246. if ( Source[ PathSeparatorIndex ] != '\\' ) {
  247. strcpy( RelativePath, TargetAbsName );
  248. return;
  249. }
  250. i = PathSeparatorIndex + 1;
  251. //
  252. // Now continue to walk down source path and insert a "..\" in the result
  253. // for each path separator encountered.
  254. //
  255. AnyParent = FALSE;
  256. while ( Source[ i ] != 0 ) {
  257. if ( Source[ i ] == '\\' ) {
  258. AnyParent = TRUE;
  259. *Output++ = '.';
  260. *Output++ = '.';
  261. *Output++ = '\\';
  262. }
  263. ++i;
  264. }
  265. if ( ! AnyParent ) {
  266. //
  267. // Relative path is below current directory.
  268. //
  269. *Output++ = '.';
  270. *Output++ = '\\';
  271. }
  272. //
  273. // Now we simply append what's remaining of the Target path from the
  274. // ancestor match point.
  275. //
  276. strcpy( Output, Target + PathSeparatorIndex + 1 );
  277. }
  278. //+---------------------------------------------------------------------------
  279. //
  280. // Function: ShouldWarnInclude
  281. //
  282. // Synopsis: Returns true if the name of the included file matches a
  283. // BUILD_UNACCEPTABLE_INCLUDES pattern or it does not match
  284. // any of the patterns specified in BUILD_ACCEPTABLE_INCLUDES.
  285. //
  286. // Arguments: [CompilandFullName] -- name of the including file
  287. // [IncludeeFullName] -- name of the included file
  288. //----------------------------------------------------------------------------
  289. BOOL
  290. ShouldWarnInclude(
  291. IN LPCSTR CompilandFullName,
  292. IN LPCSTR IncludeeFullName
  293. )
  294. {
  295. UINT i;
  296. CHAR IncludeeRelativeName[ MAX_PATH ];
  297. assert( CompilandFullName );
  298. assert( IncludeeFullName );
  299. CreateRelativePath( CompilandFullName, IncludeeFullName, IncludeeRelativeName );
  300. //
  301. // First we check for a match against any unacceptable include path
  302. // because we always want to warn about these.
  303. //
  304. for ( i = 0; UnacceptableIncludePatternList[ i ] != NULL; i++ ) {
  305. if ( DoesInstanceMatchPattern( IncludeeFullName, UnacceptableIncludePatternList[ i ] )) {
  306. return TRUE;
  307. }
  308. if ( DoesInstanceMatchPattern( IncludeeRelativeName, UnacceptableIncludePatternList[ i ] )) {
  309. return TRUE;
  310. }
  311. }
  312. //
  313. // If we get to here, the include path was not explicitly unacceptable, so
  314. // we now want to see if it matches any acceptable paths. But, if no
  315. // acceptable paths are specified, we don't want to warn.
  316. //
  317. if ( AcceptableIncludePatternList[ 0 ] == NULL ) {
  318. return FALSE;
  319. }
  320. for ( i = 0; AcceptableIncludePatternList[ i ] != NULL; i++ ) {
  321. if ( DoesInstanceMatchPattern( IncludeeFullName, AcceptableIncludePatternList[ i ] )) {
  322. return FALSE;
  323. }
  324. if ( DoesInstanceMatchPattern( IncludeeRelativeName, AcceptableIncludePatternList[ i ] )) {
  325. return FALSE;
  326. }
  327. }
  328. return TRUE;
  329. }
  330. //+---------------------------------------------------------------------------
  331. //
  332. // Function: CheckIncludeForWarning
  333. //
  334. // Synopsis: Warnings if the dependency does not respect the
  335. // BUILD_UNACCEPTABLE_INCLUDES or BUILD_ACCEPTABLE_INCLUDES
  336. // restristions. Works with build -#.
  337. //
  338. // Arguments: [CompilandDir]
  339. // [CompilandName]
  340. // [IncluderDir]
  341. // [IncluderName]
  342. // [IncludeeDir]
  343. // [IncludeeName]
  344. //----------------------------------------------------------------------------
  345. VOID
  346. CheckIncludeForWarning(
  347. IN LPCSTR CompilandDir,
  348. IN LPCSTR CompilandName,
  349. IN LPCSTR IncluderDir,
  350. IN LPCSTR IncluderName,
  351. IN LPCSTR IncludeeDir,
  352. IN LPCSTR IncludeeName
  353. )
  354. {
  355. CHAR CompilandFullName[ MAX_PATH ];
  356. CHAR IncluderFullName[ MAX_PATH ];
  357. CHAR IncludeeFullName[ MAX_PATH ];
  358. assert( CompilandDir );
  359. assert( CompilandName );
  360. assert( IncluderDir );
  361. assert( IncluderName );
  362. assert( IncludeeDir );
  363. assert( IncludeeName );
  364. CombinePaths( CompilandDir, CompilandName, CompilandFullName );
  365. CombinePaths( IncluderDir, IncluderName, IncluderFullName );
  366. CombinePaths( IncludeeDir, IncludeeName, IncludeeFullName );
  367. _strlwr( CompilandFullName );
  368. _strlwr( IncluderFullName );
  369. _strlwr( IncludeeFullName );
  370. if ( IncFile ) {
  371. fprintf(
  372. IncFile,
  373. "%s includes %s\r\n",
  374. IncluderFullName,
  375. IncludeeFullName
  376. );
  377. }
  378. if ( ShouldWarnInclude( CompilandFullName, IncludeeFullName )) {
  379. if ( strcmp( IncluderFullName, CompilandFullName ) == 0 ) {
  380. if ( WrnFile ) {
  381. fprintf(
  382. WrnFile,
  383. "WARNING: %s includes %s\n",
  384. CompilandFullName,
  385. IncludeeFullName
  386. );
  387. }
  388. if ( fShowWarningsOnScreen ) {
  389. BuildMsgRaw(
  390. "WARNING: %s includes %s\n",
  391. CompilandFullName,
  392. IncludeeFullName
  393. );
  394. }
  395. }
  396. else {
  397. if ( WrnFile ) {
  398. fprintf(
  399. WrnFile,
  400. "WARNING: %s includes %s through %s\n",
  401. CompilandFullName,
  402. IncludeeFullName,
  403. IncluderFullName
  404. );
  405. }
  406. if ( fShowWarningsOnScreen ) {
  407. BuildMsgRaw(
  408. "WARNING: %s includes %s through %s\n",
  409. CompilandFullName,
  410. IncludeeFullName,
  411. IncluderFullName
  412. );
  413. }
  414. }
  415. }
  416. }