Source code of Windows XP (NT5)
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.

815 lines
24 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1989 - 1994
  5. //
  6. // File: buildscn.c
  7. //
  8. // Contents: Directory and File scanning functions for Build.exe
  9. //
  10. //
  11. // History: 16-May-89 SteveWo Created
  12. // ... see SLM logs
  13. // 26-Jul-94 LyleC Cleanup/Add pass0 support
  14. //
  15. //----------------------------------------------------------------------------
  16. #include "build.h"
  17. //+---------------------------------------------------------------------------
  18. //
  19. // Function: AddShowDir
  20. //
  21. // Synopsis: Add a directory to the ShowDir array
  22. //
  23. //----------------------------------------------------------------------------
  24. VOID
  25. AddShowDir(DIRREC *pdr)
  26. {
  27. AssertDir(pdr);
  28. if (CountShowDirs >= MAX_BUILD_DIRECTORIES) {
  29. static BOOL fError = FALSE;
  30. if (!fError) {
  31. BuildError(
  32. "Show Directory table overflow, using first %u entries\n",
  33. MAX_BUILD_DIRECTORIES);
  34. fError = TRUE;
  35. }
  36. }
  37. else {
  38. ShowDirs[CountShowDirs++] = pdr;
  39. }
  40. pdr->DirFlags |= DIRDB_SHOWN;
  41. }
  42. //+---------------------------------------------------------------------------
  43. //
  44. // Function: AddIncludeDir
  45. //
  46. // Synopsis: Add a directory to the IncludeDirs array
  47. //
  48. //----------------------------------------------------------------------------
  49. VOID
  50. AddIncludeDir(DIRREC *pdr, UINT *pui)
  51. {
  52. AssertDir(pdr);
  53. assert(pdr->FindCount >= 1);
  54. assert(*pui <= MAX_INCLUDE_DIRECTORIES);
  55. if (*pui >= MAX_INCLUDE_DIRECTORIES) {
  56. BuildError(
  57. "Include Directory table overflow, %u entries allowed\n",
  58. MAX_INCLUDE_DIRECTORIES);
  59. exit(16);
  60. }
  61. IncludeDirs[(*pui)++] = pdr;
  62. }
  63. //+---------------------------------------------------------------------------
  64. //
  65. // Function: ScanGlobalIncludeDirectory
  66. //
  67. // Synopsis: Scans a global include directory and adds it to the
  68. // IncludeDir array.
  69. //
  70. //----------------------------------------------------------------------------
  71. VOID
  72. ScanGlobalIncludeDirectory(LPSTR path)
  73. {
  74. DIRREC *pdr;
  75. if ((pdr = ScanDirectory(path)) != NULL) {
  76. AddIncludeDir(pdr, &CountIncludeDirs);
  77. pdr->DirFlags |= DIRDB_GLOBAL_INCLUDES;
  78. if (fShowTreeIncludes && !(pdr->DirFlags & DIRDB_SHOWN)) {
  79. AddShowDir(pdr);
  80. }
  81. }
  82. }
  83. //+---------------------------------------------------------------------------
  84. //
  85. // Function: ScanIncludeEnv
  86. //
  87. // Synopsis: Scans all include directories specified in the INCLUDE
  88. // environment variable.
  89. //
  90. // Arguments: [IncludeEnv] -- value of the INCLUDE environment variable.
  91. //
  92. // Notes: The INCLUDE variable is a string with a list of directories
  93. // separated by semicolons (;).
  94. //
  95. //----------------------------------------------------------------------------
  96. VOID
  97. ScanIncludeEnv(
  98. LPSTR IncludeEnv
  99. )
  100. {
  101. char path[DB_MAX_PATH_LENGTH] = {0};
  102. LPSTR IncDir, IncDirEnd;
  103. UINT cb;
  104. if (!IncludeEnv) {
  105. return;
  106. }
  107. if (DEBUG_1) {
  108. BuildMsgRaw("ScanIncludeEnv(%s)\n", IncludeEnv);
  109. }
  110. IncDir = IncludeEnv;
  111. while (*IncDir) {
  112. IncDir++;
  113. }
  114. while (IncDir > IncludeEnv) {
  115. IncDirEnd = IncDir;
  116. while (IncDir > IncludeEnv) {
  117. if (*--IncDir == ';') {
  118. break;
  119. }
  120. }
  121. if (*IncDir == ';') {
  122. if (cb = (UINT)(IncDirEnd-IncDir-1)) {
  123. strncpy( path, IncDir+1, cb );
  124. }
  125. } else {
  126. if (cb = (UINT)(IncDirEnd-IncDir)) {
  127. strncpy( path, IncDir, cb );
  128. }
  129. }
  130. if (cb) {
  131. path[ cb ] = '\0';
  132. while (path[ 0 ] == ' ') {
  133. strcpy( path, &path[ 1 ] );
  134. cb--;
  135. }
  136. while (cb && path[--cb] == ' ') {
  137. path[ cb ] = '\0';
  138. }
  139. if (path[0]) {
  140. ScanGlobalIncludeDirectory(path);
  141. }
  142. }
  143. }
  144. }
  145. //+---------------------------------------------------------------------------
  146. //
  147. // Function: ScanSubDir
  148. //
  149. // Synopsis: Scans all the files in the given directory, sets the
  150. // directory flags appropriately (e.g. DIRDB_SOURCES, etc),
  151. // and adds a list of interesting files to the Files list in
  152. // the DirDB structure for the directory.
  153. //
  154. // Arguments: [pszDir] -- Name of directory to scan
  155. // [pdr] -- [out] Filled in DIRREC on return
  156. //
  157. // Notes: An 'interesting' file is one which has a recognized
  158. // extension. See the InsertFileDB and MatchFileDesc
  159. // functions for more info.
  160. //
  161. //----------------------------------------------------------------------------
  162. VOID
  163. ScanSubDir(LPSTR pszDir, DIRREC *pdr)
  164. {
  165. char FileName[DB_MAX_PATH_LENGTH];
  166. FILEREC *FileDB, **FileDBNext;
  167. WIN32_FIND_DATA FindFileData;
  168. HDIR FindHandle;
  169. ULONG DateTime;
  170. USHORT Attr;
  171. strcat(pszDir, "\\");
  172. strcat(pszDir, "*.*");
  173. pdr->DirFlags |= DIRDB_SCANNED;
  174. FindHandle = FindFirstFile(pszDir, &FindFileData);
  175. if (FindHandle == (HDIR)INVALID_HANDLE_VALUE) {
  176. if (DEBUG_1) {
  177. BuildMsg("FindFirstFile(%s) failed.\n", pszDir);
  178. }
  179. return;
  180. }
  181. do {
  182. Attr = (USHORT)(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
  183. if ((Attr & FILE_ATTRIBUTE_DIRECTORY) &&
  184. (!strcmp(FindFileData.cFileName, ".") ||
  185. !strcmp(FindFileData.cFileName, ".."))) {
  186. continue;
  187. }
  188. CopyString(FileName, FindFileData.cFileName, TRUE);
  189. FileTimeToDosDateTime(&FindFileData.ftLastWriteTime,
  190. ((LPWORD) &DateTime) + 1,
  191. (LPWORD) &DateTime);
  192. if ((pdr->DirFlags & DIRDB_NEW) == 0 &&
  193. (FileDB = LookupFileDB(pdr, FileName)) != NULL) {
  194. if (FileDB->FileFlags & FILEDB_PASS0)
  195. pdr->DirFlags |= DIRDB_PASS0;
  196. //
  197. // Clear the file missing flag, since we know the file exists now.
  198. // This flag may be set if the file was generated during pass zero.
  199. //
  200. if (FileDB->FileFlags & FILEDB_FILE_MISSING)
  201. FileDB->FileFlags &= ~FILEDB_FILE_MISSING;
  202. //
  203. // The time we last stored for this file is different than the
  204. // actual time on the file, so force it to be rescanned.
  205. //
  206. if (FileDB->DateTime != DateTime) {
  207. if (FileDB->FileFlags & (FILEDB_SOURCE | FILEDB_HEADER)) {
  208. FileDB->FileFlags &= ~FILEDB_SCANNED;
  209. }
  210. else {
  211. FileDB->FileFlags |= FILEDB_SCANNED;
  212. }
  213. if (DEBUG_1) {
  214. BuildMsg(
  215. "%s - DateTime (%lx != %lx)\n",
  216. FileDB->Name,
  217. FileDB->DateTime,
  218. DateTime);
  219. }
  220. FileDB->DateTime = DateTime;
  221. FileDB->Attr = Attr;
  222. }
  223. else {
  224. FileDB->FileFlags |= FILEDB_SCANNED;
  225. }
  226. }
  227. else {
  228. FileDB = InsertFileDB(pdr, FileName, DateTime, Attr, 0);
  229. }
  230. } while (FindNextFile(FindHandle, &FindFileData));
  231. FindClose(FindHandle);
  232. if ((pdr->DirFlags & DIRDB_DIRS) && (pdr->DirFlags & DIRDB_SOURCES))
  233. {
  234. BuildError("%s\\sources. unexpected in directory with DIRS file\n",
  235. pdr->Name);
  236. BuildError("Ignoring %s\\sources.\n", pdr->Name);
  237. pdr->DirFlags &= ~DIRDB_SOURCES;
  238. }
  239. //
  240. // Scan each file in this directory unless using QuickZero
  241. //
  242. if (fQuickZero && fFirstScan)
  243. {
  244. return;
  245. }
  246. FileDBNext = &pdr->Files;
  247. while (FileDB = *FileDBNext) {
  248. if (!(FileDB->FileFlags & (FILEDB_DIR | FILEDB_SCANNED))) {
  249. if (ScanFile(FileDB)) {
  250. AllDirsModified = TRUE;
  251. }
  252. }
  253. FileDBNext = &FileDB->Next;
  254. }
  255. DeleteUnscannedFiles(pdr);
  256. }
  257. //+---------------------------------------------------------------------------
  258. //
  259. // Function: ScanDirectory
  260. //
  261. // Synopsis: Tries to find the given directory in the database, and if
  262. // not found calls ScanSubDir.
  263. //
  264. // Arguments: [pszDir] -- Directory to scan
  265. //
  266. // Returns: Filled in DIRREC structure for the directory.
  267. //
  268. // Notes: If fQuicky (-z or -Z options) are set, then instead of calling
  269. // ScanSubDir, which is long, it just checks for known files, like
  270. // 'sources' for 'makefile' to determine whether or not the
  271. // directory should be compiled.
  272. //
  273. //----------------------------------------------------------------------------
  274. PDIRREC
  275. ScanDirectory(LPSTR pszDir)
  276. {
  277. DIRREC *pdr;
  278. char FullPath[DB_MAX_PATH_LENGTH];
  279. if (DEBUG_1) {
  280. BuildMsgRaw("ScanDirectory(%s)\n", pszDir);
  281. }
  282. if (!CanonicalizePathName(pszDir, CANONICALIZE_DIR, FullPath)) {
  283. if (DEBUG_1) {
  284. BuildMsgRaw("CanonicalizePathName failed\n");
  285. }
  286. return(NULL);
  287. }
  288. pszDir = FullPath;
  289. if ((pdr = LoadDirDB(pszDir)) == NULL) {
  290. return(NULL);
  291. }
  292. if (fQuicky && (!fQuickZero)) {
  293. if (!(pdr->DirFlags & DIRDB_SCANNED)) {
  294. pdr->DirFlags |= DIRDB_SCANNED;
  295. if (ProbeFile(pdr->Name, "sources") != -1) {
  296. pdr->DirFlags |= DIRDB_SOURCES | DIRDB_MAKEFILE;
  297. }
  298. else
  299. if (ProbeFile(pdr->Name, "mydirs") != -1 ||
  300. ProbeFile(pdr->Name, "dirs") != -1 ||
  301. ProbeFile(pdr->Name, pszTargetDirs) != -1) {
  302. pdr->DirFlags |= DIRDB_DIRS;
  303. if (ProbeFile(pdr->Name, "makefil0") != -1) {
  304. pdr->DirFlags |= DIRDB_MAKEFIL0;
  305. }
  306. if (ProbeFile(pdr->Name, "makefil1") != -1) {
  307. pdr->DirFlags |= DIRDB_MAKEFIL1;
  308. }
  309. if (ProbeFile(pdr->Name, "makefile") != -1) {
  310. pdr->DirFlags |= DIRDB_MAKEFILE;
  311. }
  312. }
  313. }
  314. return(pdr);
  315. }
  316. if (pdr->DirFlags & DIRDB_SCANNED) {
  317. return(pdr);
  318. }
  319. if (!RecurseLevel && fNoisyScan) {
  320. ClearLine();
  321. BuildMsgRaw(" Scanning %s ", pszDir);
  322. if (fDebug || !(BOOL) _isatty(_fileno(stderr))) {
  323. BuildMsgRaw(szNewLine);
  324. }
  325. }
  326. ScanSubDir(pszDir, pdr);
  327. if (!RecurseLevel) {
  328. ClearLine();
  329. }
  330. return(pdr);
  331. }
  332. #define BUILD_TLIB_INCLUDE_STMT "importlib"
  333. #define BUILD_TLIB_INCLUDE_STMT_LENGTH (sizeof( BUILD_TLIB_INCLUDE_STMT )-1)
  334. #define BUILD_MIDL_INCLUDE_STMT "import"
  335. #define BUILD_MIDL_INCLUDE_STMT_LENGTH (sizeof( BUILD_MIDL_INCLUDE_STMT )-1)
  336. #define BUILD_RC_INCLUDE_STMT "rcinclude"
  337. #define BUILD_RC_INCLUDE_STMT_LENGTH (sizeof( BUILD_RC_INCLUDE_STMT )-1)
  338. #define BUILD_ASN_INCLUDE_STMT "--<"
  339. #define BUILD_ASN_INCLUDE_STMT_LENGTH (sizeof( BUILD_ASN_INCLUDE_STMT )-1)
  340. #define BUILD_INCLUDE_STMT "include"
  341. #define BUILD_INCLUDE_STMT_LENGTH (sizeof( BUILD_INCLUDE_STMT )-1)
  342. #define BUILD_VER_COMMENT "/*++ BUILD Version: "
  343. #define BUILD_VER_COMMENT_LENGTH (sizeof( BUILD_VER_COMMENT )-1)
  344. #define BUILD_MASM_VER_COMMENT ";;;; BUILD Version: "
  345. #define BUILD_MASM_VER_COMMENT_LENGTH (sizeof( BUILD_MASM_VER_COMMENT )-1)
  346. //+---------------------------------------------------------------------------
  347. //
  348. // Function: IsIncludeStatement
  349. //
  350. // Synopsis: Tries to determine whether or not a given line contains an
  351. // include statement (e.g. #include <foobar.h> ).
  352. //
  353. // Arguments: [pfr] -- FILEREC of file being scanned
  354. // [p] -- Current line of file
  355. //
  356. // Returns: NULL if line is not an include statment. Returns pointer to
  357. // beginning of filename if it is (e.g. <foobar.h> ).
  358. //
  359. // Notes: The returned filename includes the surrounding quotes or
  360. // brackets, if any. Also, the pointer is just a pointer into
  361. // the given string, not a separate copy.
  362. //
  363. // Supported statements are:
  364. // All file types: #include <filename> and #include "filename"
  365. // MIDL files: import "filename"
  366. // RC files: rcinclude filename
  367. // MKTYPLIB files: importlib("filename")
  368. //
  369. //----------------------------------------------------------------------------
  370. #define IsTokenPrefix0(psz, szToken, cchToken) \
  371. (strncmp((psz), (szToken), (cchToken)) == 0)
  372. #define IsTokenPrefix(psz, szToken, cchToken) \
  373. (IsTokenPrefix0((psz), (szToken), (cchToken)) && \
  374. (psz)[cchToken] != '\0')
  375. #define IsTokenMatch(psz, szToken, cchToken) \
  376. (IsTokenPrefix((psz), (szToken), (cchToken)) && \
  377. !iscsym((psz)[cchToken]))
  378. #define IsCiTokenPrefix0(psz, szToken, cchToken) \
  379. (_strnicmp((psz), (szToken), (cchToken)) == 0)
  380. #define IsCiTokenPrefix(psz, szToken, cchToken) \
  381. (IsCiTokenPrefix0((psz), (szToken), (cchToken)) && \
  382. (psz)[cchToken] != '\0')
  383. #define IsCiTokenMatch(psz, szToken, cchToken) \
  384. (IsCiTokenPrefix((psz), (szToken), (cchToken)) && \
  385. !iscsym((psz)[cchToken]))
  386. LPSTR
  387. IsIncludeStatement(FILEREC *pfr, LPSTR p)
  388. {
  389. if (!p || *p == '\0')
  390. return NULL;
  391. if (!(pfr->FileFlags & (FILEDB_MASM | FILEDB_MIDL | FILEDB_MKTYPLIB | FILEDB_RC | FILEDB_ASN))) {
  392. if (*p != '#') {
  393. return(NULL);
  394. }
  395. }
  396. if (*p == '#')
  397. p++;
  398. while (isspace(*p)) {
  399. p++;
  400. }
  401. if (IsTokenMatch(p, BUILD_INCLUDE_STMT, BUILD_INCLUDE_STMT_LENGTH)) {
  402. p += BUILD_INCLUDE_STMT_LENGTH;
  403. }
  404. else
  405. if ((pfr->FileFlags & FILEDB_MASM) &&
  406. IsCiTokenMatch(p, BUILD_INCLUDE_STMT, BUILD_INCLUDE_STMT_LENGTH)) {
  407. p += BUILD_INCLUDE_STMT_LENGTH;
  408. }
  409. else
  410. if ((pfr->FileFlags & FILEDB_MIDL) &&
  411. IsTokenMatch(p, BUILD_MIDL_INCLUDE_STMT, BUILD_MIDL_INCLUDE_STMT_LENGTH)) {
  412. p += BUILD_MIDL_INCLUDE_STMT_LENGTH;
  413. }
  414. else
  415. if ((pfr->FileFlags & FILEDB_RC) &&
  416. IsTokenMatch(p, BUILD_RC_INCLUDE_STMT, BUILD_RC_INCLUDE_STMT_LENGTH)) {
  417. p += BUILD_RC_INCLUDE_STMT_LENGTH;
  418. }
  419. else
  420. if ((pfr->FileFlags & FILEDB_ASN) &&
  421. IsTokenPrefix0(p, BUILD_ASN_INCLUDE_STMT, BUILD_ASN_INCLUDE_STMT_LENGTH)) {
  422. p += BUILD_ASN_INCLUDE_STMT_LENGTH;
  423. }
  424. else
  425. if ((pfr->FileFlags & FILEDB_MKTYPLIB) &&
  426. IsTokenMatch(p, BUILD_TLIB_INCLUDE_STMT, BUILD_TLIB_INCLUDE_STMT_LENGTH)) {
  427. p += BUILD_TLIB_INCLUDE_STMT_LENGTH;
  428. while (isspace(*p)) {
  429. p++;
  430. }
  431. if (*p == '(') // Skip the open paren and get to the quote.
  432. p++;
  433. }
  434. else {
  435. return(NULL);
  436. }
  437. while (isspace(*p)) {
  438. p++;
  439. }
  440. return(p);
  441. }
  442. //+---------------------------------------------------------------------------
  443. //
  444. // Function: IsPragmaHdrStop
  445. //
  446. // Synopsis: Determines if the given line is a #pragma hdrstop line
  447. //
  448. // Arguments: [p] -- String to analyze
  449. //
  450. // Returns: TRUE if the line is a pragma hdrstop
  451. //
  452. //----------------------------------------------------------------------------
  453. BOOL
  454. IsPragmaHdrStop(LPSTR p)
  455. {
  456. static char szPragma[] = "pragma";
  457. static char szHdrStop[] = "hdrstop";
  458. if (*p == '#') {
  459. while (*++p == ' ') {
  460. ;
  461. }
  462. if (strncmp(p, szPragma, sizeof(szPragma) - 1) == 0 &&
  463. *(p += sizeof(szPragma) - 1) == ' ') {
  464. while (*p == ' ') {
  465. p++;
  466. }
  467. if (strncmp(p, szHdrStop, sizeof(szHdrStop) - 1) == 0 &&
  468. !iscsym(p[sizeof(szHdrStop) - 1])) {
  469. return(TRUE);
  470. }
  471. }
  472. }
  473. return(FALSE);
  474. }
  475. //+---------------------------------------------------------------------------
  476. //
  477. // Function: ScanFile
  478. //
  479. // Synopsis: Scans the given file to determine files which it includes.
  480. //
  481. // Arguments: [FileDB] -- File to scan.
  482. //
  483. // Returns: TRUE if successful
  484. //
  485. // Notes: This function is a nop if the given file does not have either
  486. // the FILEDB_SOURCE or FILEDB_HEADER flag set.
  487. // (see InsertSourceDB)
  488. //
  489. // Note that the performance of this function is critical since
  490. // it is called for every file in each directory.
  491. //
  492. //----------------------------------------------------------------------------
  493. #define ASN_NONE 0 // not in Asn INCLUDES statement
  494. #define ASN_START 1 // expectimg "INCLUDES" token
  495. #define ASN_FILENAME 2 // expecting a quoted "filename"
  496. #define ASN_COMMA 3 // expecting end token (">--") or comma
  497. #define ASN_CONTINUATION 8 // expecting comment token first
  498. char *
  499. AsnStateToString(UINT AsnState)
  500. {
  501. static char buf[100];
  502. char *psz;
  503. switch (AsnState & ~ASN_CONTINUATION) {
  504. case ASN_NONE: psz = "None"; break;
  505. case ASN_START: psz = "Start"; break;
  506. case ASN_FILENAME: psz = "Filename"; break;
  507. case ASN_COMMA: psz = "Comma"; break;
  508. default: psz = "???"; break;
  509. }
  510. sprintf(buf, "%s%s", psz, (AsnState & ASN_CONTINUATION)? "+Cont" : "");
  511. return(buf);
  512. }
  513. BOOL
  514. ScanFile(
  515. PFILEREC FileDB
  516. )
  517. {
  518. FILE *FileHandle;
  519. char CloseQuote;
  520. LPSTR p;
  521. LPSTR IncludeFileName, TextLine;
  522. BOOL fFirst = TRUE;
  523. USHORT IncFlags = 0;
  524. UINT i, cline;
  525. UINT AsnState = ASN_NONE;
  526. if ((FileDB->FileFlags & (FILEDB_SOURCE | FILEDB_HEADER)) == 0) {
  527. FileDB->FileFlags |= FILEDB_SCANNED;
  528. return(TRUE);
  529. }
  530. //
  531. // Don't scan non-pass-zero files if we're doing pass zero.
  532. //
  533. if (fPassZero && (FileDB->FileFlags & FILEDB_PASS0) == 0)
  534. return TRUE;
  535. if (!SetupReadFile(
  536. FileDB->Dir->Name,
  537. FileDB->Name,
  538. FileDB->pszCommentToEOL,
  539. &FileHandle)) {
  540. return(FALSE);
  541. }
  542. if (!RecurseLevel && fNoisyScan) {
  543. ClearLine();
  544. BuildMsgRaw(
  545. " Scanning %s ",
  546. FormatPathName(FileDB->Dir->Name, FileDB->Name));
  547. if (!(BOOL) _isatty(_fileno(stderr))) {
  548. BuildMsgRaw(szNewLine);
  549. }
  550. }
  551. FileDB->SourceLines = 0;
  552. FileDB->Version = 0;
  553. MarkIncludeFileRecords( FileDB );
  554. FileDB->FileFlags |= FILEDB_SCANNED;
  555. AllDirsModified = TRUE;
  556. while ((TextLine = ReadLine(FileHandle)) != NULL) {
  557. if (fFirst) {
  558. fFirst = FALSE;
  559. if (FileDB->FileFlags & FILEDB_HEADER) {
  560. if (FileDB->FileFlags & FILEDB_MASM) {
  561. if (!strncmp( TextLine,
  562. BUILD_MASM_VER_COMMENT,
  563. BUILD_MASM_VER_COMMENT_LENGTH)) {
  564. FileDB->Version = (USHORT)
  565. atoi( TextLine + BUILD_MASM_VER_COMMENT_LENGTH);
  566. }
  567. }
  568. else
  569. if (!strncmp( TextLine,
  570. BUILD_VER_COMMENT,
  571. BUILD_VER_COMMENT_LENGTH)) {
  572. FileDB->Version = (USHORT)
  573. atoi( TextLine + BUILD_VER_COMMENT_LENGTH);
  574. }
  575. }
  576. }
  577. if (AsnState != ASN_NONE) {
  578. p = TextLine;
  579. }
  580. else {
  581. p = IsIncludeStatement(FileDB, TextLine);
  582. }
  583. if (p != NULL) {
  584. USHORT IncFlagsNew = IncFlags;
  585. if (FileDB->FileFlags & FILEDB_ASN) {
  586. if (AsnState & ASN_CONTINUATION) {
  587. if (p[0] != '-' || p[1] != '-') {
  588. AsnState = ASN_NONE; // ignore includes and ...
  589. p = NULL;
  590. break; // get next line
  591. }
  592. p += 2;
  593. AsnState &= ~ASN_CONTINUATION;
  594. }
  595. moreasn:
  596. while (p != NULL) {
  597. while (isspace(*p)) {
  598. p++;
  599. }
  600. if (*p == '\0') {
  601. AsnState |= ASN_CONTINUATION;
  602. goto nextline; // get next line
  603. }
  604. switch (AsnState) {
  605. case ASN_NONE:
  606. AsnState = ASN_START;
  607. continue; // re-enter state machine
  608. case ASN_START:
  609. if (!IsTokenPrefix0(
  610. p,
  611. "INCLUDES",
  612. sizeof("INCLUDES") - 1)) {
  613. goto terminate;
  614. }
  615. AsnState = ASN_FILENAME;
  616. p += sizeof("INCLUDES") - 1;
  617. continue; // re-enter state machine
  618. case ASN_FILENAME:
  619. if (*p != '"') {
  620. goto terminate;
  621. }
  622. AsnState = ASN_COMMA;
  623. goto parsefilename;
  624. case ASN_COMMA:
  625. if (*p == '>' && p[1] == '-' && p[2] == '-') {
  626. goto terminate;
  627. }
  628. if (*p != ',') {
  629. goto terminate;
  630. }
  631. p++;
  632. AsnState = ASN_FILENAME;
  633. continue; // re-enter state machine
  634. }
  635. assert(FALSE); // Bad AsnState
  636. terminate:
  637. AsnState = ASN_NONE; // ignore includes statement, & ...
  638. nextline:
  639. p = NULL; // get next line
  640. break;
  641. }
  642. }
  643. parsefilename:
  644. if (p != NULL) {
  645. CloseQuote = (UCHAR) 0xff;
  646. if (*p == '<') {
  647. p++;
  648. CloseQuote = '>';
  649. }
  650. else
  651. if (*p == '"') {
  652. p++;
  653. IncFlagsNew |= INCLUDEDB_LOCAL;
  654. CloseQuote = '"';
  655. }
  656. else
  657. if (FileDB->FileFlags & FILEDB_MASM) {
  658. IncFlagsNew |= INCLUDEDB_LOCAL;
  659. CloseQuote = ';';
  660. }
  661. IncludeFileName = p;
  662. while (*p != '\0' && *p != CloseQuote && *p != ' ') {
  663. p++;
  664. }
  665. if (CloseQuote == ';' && (*p == ' ' || *p == '\0')) {
  666. CloseQuote = *p;
  667. }
  668. if (*p != CloseQuote || CloseQuote == (UCHAR) 0xff) {
  669. BuildError(
  670. "%s - invalid include statement: %s\n",
  671. FormatPathName(FileDB->Dir->Name, FileDB->Name),
  672. TextLine);
  673. break;
  674. }
  675. *p = '\0';
  676. CopyString(IncludeFileName, IncludeFileName, TRUE);
  677. for (i = 0; i < CountExcludeIncs; i++) {
  678. if (!strcmp(IncludeFileName, ExcludeIncs[i])) {
  679. IncludeFileName = NULL;
  680. break;
  681. }
  682. }
  683. if (IncludeFileName != NULL) {
  684. InsertIncludeDB(FileDB, IncludeFileName, IncFlagsNew);
  685. }
  686. if (FileDB->FileFlags & FILEDB_ASN) {
  687. p++;
  688. goto moreasn;
  689. }
  690. }
  691. }
  692. else
  693. if (IncFlags == 0 &&
  694. (FileDB->FileFlags & (FILEDB_ASM | FILEDB_MASM | FILEDB_MIDL | FILEDB_ASN | FILEDB_RC | FILEDB_HEADER)) == 0 &&
  695. IsPragmaHdrStop(TextLine)) {
  696. IncFlags = INCLUDEDB_POST_HDRSTOP;
  697. }
  698. }
  699. CloseReadFile(&cline);
  700. FileDB->SourceLines = cline;
  701. DeleteIncludeFileRecords( FileDB );
  702. if (!RecurseLevel) {
  703. ClearLine();
  704. }
  705. return(TRUE);
  706. }