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.

2084 lines
62 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1989 - 1994
  5. //
  6. // File: builddb.c
  7. //
  8. // Contents: Contains the file and directory database manipulation
  9. // functions.
  10. //
  11. // History: 16-May-94 SteveWo Created
  12. // ... see SLM logs
  13. // 26-Jul-94 LyleC Cleanup/Add Pass0 Support
  14. //
  15. //----------------------------------------------------------------------------
  16. #include "build.h"
  17. BOOL fAssertCleanTree = FALSE;
  18. typedef struct _FLAGSTRINGS {
  19. ULONG Mask;
  20. LPSTR pszName;
  21. } FLAGSTRINGS;
  22. FLAGSTRINGS DirFlags[] = {
  23. { DIRDB_SOURCES, "Sources"},
  24. { DIRDB_DIRS, "Dirs"},
  25. { DIRDB_MAKEFILE, "Makefile"},
  26. { DIRDB_MAKEFIL0, "Makefil0"},
  27. { DIRDB_TARGETFILE0, "Targetfile0"},
  28. { DIRDB_TARGETFILES, "Targetfiles"},
  29. { DIRDB_RESOURCE, "Resource"},
  30. { DIRDB_PASS0, "PassZero"},
  31. { DIRDB_SOURCES_SET, "SourcesSet"},
  32. { DIRDB_CHICAGO_INCLUDES, "ChicagoIncludes"},
  33. { DIRDB_NEW, "New"},
  34. { DIRDB_SCANNED, "Scanned"},
  35. { DIRDB_SHOWN, "Shown"},
  36. { DIRDB_GLOBAL_INCLUDES, "GlobalIncludes"},
  37. { DIRDB_SYNCHRONIZE_BLOCK, "SynchronizeBlock"},
  38. { DIRDB_SYNCHRONIZE_PASS2_BLOCK, "SynchronizePass2Block"},
  39. { DIRDB_SYNCHRONIZE_DRAIN, "SynchronizeDrain"},
  40. { DIRDB_SYNCHRONIZE_PASS2_DRAIN, "SynchronizePass2Drain"},
  41. { DIRDB_COMPILENEEDED, "CompileNeeded"},
  42. { DIRDB_COMPILEERRORS, "CompileErrors"},
  43. { DIRDB_SOURCESREAD, "SourcesRead"},
  44. { DIRDB_DLLTARGET, "DllTarget"},
  45. { DIRDB_LINKNEEDED, "LinkNeeded"},
  46. { DIRDB_FORCELINK, "ForceLink"},
  47. { DIRDB_PASS0NEEDED, "Pass0Needed"},
  48. { DIRDB_MAKEFIL1, "Makefil1"},
  49. { DIRDB_CHECKED_ALT_DIR, "CheckedAltDir"},
  50. { DIRDB_MANAGED_CODE, "ManagedCode"},
  51. { DIRDB_SYNC_PRODUCES, "BuildProduces"},
  52. { DIRDB_SYNC_CONSUMES, "BuildConsumes"},
  53. { 0, NULL},
  54. };
  55. FLAGSTRINGS FileFlags[] = {
  56. { FILEDB_SOURCE, "Source"},
  57. { FILEDB_DIR, "Dir"},
  58. { FILEDB_HEADER, "Header"},
  59. { FILEDB_ASM, "Asm"},
  60. { FILEDB_MASM, "Masm"},
  61. { FILEDB_RC, "Rc"},
  62. { FILEDB_C, "C"},
  63. { FILEDB_MIDL, "Midl"},
  64. { FILEDB_ASN, "Asn"},
  65. { FILEDB_JAVA, "Java"},
  66. { FILEDB_MOF, "ManagedObjectFormat"},
  67. { FILEDB_CSHARP, "C#"},
  68. { FILEDB_SCANNED, "Scanned"},
  69. { FILEDB_OBJECTS_LIST, "ObjectsList"},
  70. { FILEDB_FILE_MISSING, "FileMissing"},
  71. { FILEDB_MKTYPLIB, "MkTypeLib"},
  72. { FILEDB_MULTIPLEPASS, "MultiplePass"},
  73. { FILEDB_PASS0, "PassZero"},
  74. { FILEDB_VBP, "VB"},
  75. { FILEDB_VB_NET, "VB.NET"},
  76. { 0, NULL},
  77. };
  78. FLAGSTRINGS IncludeFlags[] = {
  79. { INCLUDEDB_LOCAL, "Local"},
  80. { INCLUDEDB_POST_HDRSTOP, "PostHdrStop"},
  81. { INCLUDEDB_MISSING, "Missing"},
  82. { INCLUDEDB_GLOBAL, "Global"},
  83. { INCLUDEDB_SNAPPED, "Snapped"},
  84. { INCLUDEDB_CYCLEALLOC, "CycleAlloc"},
  85. { INCLUDEDB_CYCLEROOT, "CycleRoot"},
  86. { INCLUDEDB_CYCLEORPHAN, "CycleOrphan"},
  87. { 0, NULL},
  88. };
  89. FLAGSTRINGS SourceFlags[] = {
  90. { SOURCEDB_SOURCES_LIST, "SourcesList"},
  91. { SOURCEDB_FILE_MISSING, "FileMissing"},
  92. { SOURCEDB_PCH, "Pch"},
  93. { SOURCEDB_OUT_OF_DATE, "OutOfDate"},
  94. { SOURCEDB_COMPILE_NEEDED, "CompileNeeded"},
  95. { 0, NULL},
  96. };
  97. //
  98. // Function prototypes
  99. //
  100. VOID
  101. FreeFileDB(PFILEREC *FileDB);
  102. VOID
  103. PrintFlags(FILE *pf, ULONG Flags, FLAGSTRINGS *pfs);
  104. //+---------------------------------------------------------------------------
  105. //
  106. // Function: CheckSum
  107. //
  108. // Synopsis: Returns a checksum value for a string.
  109. //
  110. //----------------------------------------------------------------------------
  111. USHORT
  112. CheckSum(LPSTR psz)
  113. {
  114. USHORT sum = 0;
  115. while (*psz != '\0') {
  116. if (sum & 0x8000) {
  117. sum = ((sum << 1) | 1) + *psz++;
  118. } else {
  119. sum = (sum << 1) + *psz++;
  120. }
  121. }
  122. return (sum);
  123. }
  124. //+---------------------------------------------------------------------------
  125. //
  126. // Function: FindSourceDirDB
  127. //
  128. // Synopsis: Builds a path from the two given components and returns
  129. // a filled DIRREC structure from it.
  130. //
  131. // Arguments: [pszDir] -- Directory
  132. // [pszRelPath] -- Path relative to [pszDir]
  133. // [fTruncateFileName] -- Remove a filename from [pszRelPath]
  134. //
  135. // Returns: A filled DIRREC structure for the given directory.
  136. //
  137. // Notes: If the directory does not exist in the data base, then a
  138. // DIRREC structure will be returned with the DIRDB_NEW flag
  139. // set and no other data (i.e. the directory will not have
  140. // been scanned.)
  141. //
  142. //----------------------------------------------------------------------------
  143. DIRREC *
  144. FindSourceDirDB(
  145. LPSTR pszDir, // directory
  146. LPSTR pszRelPath, // relative path
  147. BOOL fTruncateFileName) // TRUE: drop last component of path
  148. {
  149. LPSTR pszFile;
  150. char path[DB_MAX_PATH_LENGTH] = {0};
  151. AssertPathString(pszDir);
  152. AssertPathString(pszRelPath);
  153. if ((strlen(pszDir) + sizeof("\\") + strlen(pszRelPath) + 1) > DB_MAX_PATH_LENGTH) {
  154. BuildError(
  155. "%s\\%s : Path too long - need to rebuild build.exe with larger DB_MAX_PATH_LENGTH\n",
  156. pszDir,
  157. pszRelPath);
  158. return NULL;
  159. }
  160. if (pszDir[0] == '\0') {
  161. strncpy( path, pszRelPath, sizeof(path) - 1 );
  162. } else {
  163. _snprintf(path, sizeof(path) - 1, "%s\\%s", pszDir, pszRelPath);
  164. }
  165. pszFile = path + strlen(path);
  166. if (fTruncateFileName) {
  167. while (pszFile > path) {
  168. pszFile--;
  169. if (*pszFile == '\\' || *pszFile == '/') {
  170. *pszFile = '\0';
  171. break;
  172. }
  173. }
  174. }
  175. if (!CanonicalizePathName(path, CANONICALIZE_ONLY, path)) {
  176. return (NULL);
  177. }
  178. if (DEBUG_4) {
  179. BuildMsgRaw(
  180. "FindSourceDirDB(%s, %s, %u)\n",
  181. path,
  182. pszFile,
  183. fTruncateFileName);
  184. }
  185. AssertPathString(path);
  186. return (LoadDirDB(path));
  187. }
  188. //+---------------------------------------------------------------------------
  189. //
  190. // Function: FindSourceFileDB
  191. //
  192. // Synopsis: Returns a FILEREC with information about the given file.
  193. //
  194. // Arguments: [pdr] -- DIRREC giving directory from which to start
  195. // looking for [pszRelPath]
  196. // [pszRelPath] -- Relative path from [pdr] of the file
  197. // [ppdr] -- [out] DIRREC of directory actually containing
  198. // the file. Can be NULL.
  199. //
  200. // Returns: FILEREC for file of interest.
  201. //
  202. // Notes: If the directory containing the file has not yet been scanned,
  203. // then it will be scanned using ScanDirectory().
  204. //
  205. //----------------------------------------------------------------------------
  206. FILEREC *
  207. FindSourceFileDB(
  208. DIRREC *pdr,
  209. LPSTR pszRelPath,
  210. DIRREC **ppdr)
  211. {
  212. LPSTR p, pszFile;
  213. AssertPathString(pszRelPath);
  214. if (strchr(pszRelPath, '\\') != NULL) {
  215. // There's a path component in this filename. Let's see where it points to.
  216. if ( (pszRelPath[0] == '\\') || /* Absolute from root or UNC Path */
  217. (pszRelPath[1] == ':' )) { /* drive : path */
  218. pdr = FindSourceDirDB("", pszRelPath, TRUE);
  219. } else {
  220. pdr = FindSourceDirDB(pdr->Name, pszRelPath, TRUE);
  221. }
  222. }
  223. if (ppdr != NULL) {
  224. *ppdr = pdr;
  225. }
  226. if (pdr == NULL ) {
  227. return (NULL);
  228. }
  229. pszFile = pszRelPath;
  230. for (p = pszFile; *p != '\0'; p++) {
  231. if (*p == '\\') {
  232. pszFile = p + 1;
  233. }
  234. }
  235. if (DEBUG_4) {
  236. BuildMsgRaw("FindSourceFileDB(%s, %s)\n", pdr->Name, pszFile);
  237. }
  238. //
  239. // Scan the directory containing the file if we haven't already.
  240. //
  241. if ((pdr->DirFlags & DIRDB_SCANNED) == 0) {
  242. if (DEBUG_1) {
  243. BuildMsgRaw(
  244. "FindSourceFileDB(%s, %s) Delayed scan\n",
  245. pdr->Name,
  246. pszFile);
  247. }
  248. pdr = ScanDirectory(pdr->Name);
  249. if (pdr == NULL) {
  250. return (NULL);
  251. }
  252. }
  253. return (LookupFileDB(pdr, pszFile));
  254. }
  255. //+---------------------------------------------------------------------------
  256. //
  257. // Function: InsertSourceDB
  258. //
  259. // Synopsis: Insert a file listed in SOURCES= into a list of SOURCEREC
  260. // structures.
  261. //
  262. // Arguments: [ppsrNext] -- Head of list of sources files to add to.
  263. // [pfr] -- File to be inserted.
  264. // [SubDirMask] -- Indicates what directory the file is in.
  265. // (Current, Parent, or a machine-specific dir)
  266. // [SrcFlags] -- SOURCEDB flags appropriate to this file.
  267. //
  268. // Returns: SOURCEREC that was inserted. May be ignored.
  269. //
  270. // Notes: InsertSourceDB maintains a sort order for PickFirst() based
  271. // first on the filename extension, then on the subdirectory
  272. // mask.
  273. //
  274. // Two exceptions to the alphabetic sort are:
  275. // - No extension sorts last.
  276. // - .rc extension sorts first.
  277. //
  278. // If the file is already in the list of sources then this
  279. // function just updates the flags and returns.
  280. //
  281. //----------------------------------------------------------------------------
  282. SOURCEREC *
  283. InsertSourceDB(
  284. SOURCEREC **ppsrNext,
  285. FILEREC *pfr,
  286. UCHAR SubDirMask,
  287. UCHAR SrcFlags)
  288. {
  289. SOURCEREC *psr;
  290. SOURCEREC **ppsrInsert;
  291. LPSTR pszext;
  292. BOOL fRC;
  293. AssertFile(pfr);
  294. ppsrInsert = NULL;
  295. pszext = strrchr(pfr->Name, '.');
  296. fRC = FALSE;
  297. if (pszext != NULL && _stricmp(pszext, ".rc") == 0) {
  298. fRC = TRUE;
  299. }
  300. for ( ; (psr = *ppsrNext) != NULL; ppsrNext = &psr->psrNext) {
  301. LPSTR p;
  302. int r;
  303. AssertSource(psr);
  304. if (psr->pfrSource == pfr) {
  305. assert(psr->SourceSubDirMask == SubDirMask);
  306. psr->SrcFlags = SrcFlags;
  307. return (psr);
  308. }
  309. if (ppsrInsert == NULL && pszext != NULL) {
  310. if ((p = strrchr(psr->pfrSource->Name, '.')) == NULL) {
  311. r = -1; // insert new file here
  312. } else {
  313. r = strcmp(pszext, p);
  314. if (r != 0) {
  315. if (fRC) {
  316. r = -1; // insert new RC file here
  317. } else if (strcmp(p, ".rc") == 0) {
  318. r = 1; // old RC file comes first
  319. }
  320. }
  321. }
  322. if (r < 0 || SubDirMask > psr->SourceSubDirMask) {
  323. ppsrInsert = ppsrNext;
  324. }
  325. }
  326. }
  327. AllocMem(sizeof(SOURCEREC), &psr, MT_SOURCEDB);
  328. memset(psr, 0, sizeof(*psr));
  329. SigCheck(psr->Sig = SIG_SOURCEREC);
  330. if (ppsrInsert != NULL) {
  331. ppsrNext = ppsrInsert;
  332. }
  333. psr->psrNext = *ppsrNext;
  334. *ppsrNext = psr;
  335. psr->pfrSource = pfr;
  336. pfr->FileFlags |= FILEDB_SOURCEREC_EXISTS;
  337. psr->SourceSubDirMask = SubDirMask;
  338. psr->SrcFlags = SrcFlags;
  339. return (psr);
  340. }
  341. //+---------------------------------------------------------------------------
  342. //
  343. // Function: FindSourceDB
  344. //
  345. // Synopsis: Finds the SOURCEREC in a list which corresponds to the given
  346. // FILEREC.
  347. //
  348. //----------------------------------------------------------------------------
  349. SOURCEREC *
  350. FindSourceDB(
  351. SOURCEREC *psr,
  352. FILEREC *pfr)
  353. {
  354. while (psr != NULL) {
  355. AssertSource(psr);
  356. if (psr->pfrSource == pfr) {
  357. return (psr);
  358. }
  359. psr = psr->psrNext;
  360. }
  361. return (NULL);
  362. }
  363. //+---------------------------------------------------------------------------
  364. //
  365. // Function: FreeSourceDB
  366. //
  367. // Synopsis: Frees a list of SOURCERECs
  368. //
  369. // Arguments: [ppsr] -- List to free
  370. //
  371. //----------------------------------------------------------------------------
  372. VOID
  373. FreeSourceDB(SOURCEREC **ppsr)
  374. {
  375. if (*ppsr != NULL) {
  376. SOURCEREC *psr;
  377. SOURCEREC *psrNext;
  378. psr = *ppsr;
  379. AssertSource(psr);
  380. psrNext = psr->psrNext;
  381. SigCheck(psr->Sig = 0);
  382. FreeMem(ppsr, MT_SOURCEDB);
  383. *ppsr = psrNext;
  384. }
  385. }
  386. //+---------------------------------------------------------------------------
  387. //
  388. // Function: FreeIncludeDB
  389. //
  390. //----------------------------------------------------------------------------
  391. VOID
  392. FreeIncludeDB(INCLUDEREC **ppir)
  393. {
  394. if (*ppir != NULL) {
  395. INCLUDEREC *pir;
  396. INCLUDEREC *pirNext;
  397. pir = *ppir;
  398. AssertInclude(pir);
  399. AssertCleanTree(pir, NULL); // Tree must be clean
  400. pirNext = pir->Next;
  401. SigCheck(pir->Sig = 0);
  402. FreeMem(ppir, MT_INCLUDEDB);
  403. *ppir = pirNext;
  404. }
  405. }
  406. //+---------------------------------------------------------------------------
  407. //
  408. // Function: FreeFileDB
  409. //
  410. //----------------------------------------------------------------------------
  411. VOID
  412. FreeFileDB(FILEREC **ppfr)
  413. {
  414. if (*ppfr != NULL) {
  415. FILEREC *pfr;
  416. FILEREC *pfrNext;
  417. pfr = *ppfr;
  418. AssertFile(pfr);
  419. UnsnapIncludeFiles(pfr, TRUE);
  420. while (pfr->IncludeFiles) {
  421. FreeIncludeDB(&pfr->IncludeFiles);
  422. }
  423. pfrNext = pfr->Next;
  424. SigCheck(pfr->Sig = 0);
  425. FreeMem(ppfr, MT_FILEDB);
  426. *ppfr = pfrNext;
  427. }
  428. }
  429. //+---------------------------------------------------------------------------
  430. //
  431. // Function: FreeDirDB
  432. //
  433. //----------------------------------------------------------------------------
  434. VOID
  435. FreeDirDB(DIRREC **ppdr)
  436. {
  437. if (*ppdr != NULL) {
  438. DIRREC *pdr;
  439. DIRREC *pdrNext;
  440. pdr = *ppdr;
  441. AssertDir(pdr);
  442. FreeDirData(pdr);
  443. while (pdr->Files) {
  444. FreeFileDB(&pdr->Files);
  445. }
  446. pdrNext = pdr->Next;
  447. SigCheck(pdr->Sig = 0);
  448. FreeMem(ppdr, MT_DIRDB);
  449. *ppdr = pdrNext;
  450. }
  451. }
  452. //+---------------------------------------------------------------------------
  453. //
  454. // Function: FreeAllDirs
  455. //
  456. //----------------------------------------------------------------------------
  457. VOID
  458. FreeAllDirs(VOID)
  459. {
  460. while (AllDirs != NULL) {
  461. FreeDirDB(&AllDirs);
  462. #if DBG
  463. if (fDebug & 8) {
  464. BuildMsgRaw("Freed one directory\n");
  465. PrintAllDirs();
  466. }
  467. #endif
  468. }
  469. }
  470. //+---------------------------------------------------------------------------
  471. //
  472. // Function: LookupDirDB
  473. //
  474. // Synopsis: Searches the database for a given directory.
  475. //
  476. // Arguments: [DirName] -- Directory to search for.
  477. //
  478. // Returns: DIRREC of the given directory. NULL if not found.
  479. //
  480. // Notes: If the directory is not in the database it will not be added.
  481. // Use LoadDirDB in this case.
  482. //
  483. //----------------------------------------------------------------------------
  484. PDIRREC
  485. LookupDirDB(
  486. LPSTR DirName
  487. )
  488. {
  489. PDIRREC *DirDBNext = &AllDirs;
  490. PDIRREC DirDB;
  491. USHORT sum;
  492. AssertPathString(DirName);
  493. sum = CheckSum(DirName);
  494. while (DirDB = *DirDBNext) {
  495. if (sum == DirDB->CheckSum && strcmp(DirName, DirDB->Name) == 0) {
  496. if (DirDB->FindCount == 0 && fForce) {
  497. FreeDirDB(DirDBNext);
  498. return (NULL);
  499. }
  500. DirDB->FindCount++;
  501. // Move to head of list to make next lookup faster
  502. // *DirDBNext = DirDB->Next;
  503. // DirDB->Next = AllDirs;
  504. // AllDirs = DirDB;
  505. return (DirDB);
  506. }
  507. DirDBNext = &DirDB->Next;
  508. }
  509. return (NULL);
  510. }
  511. PDIRREC
  512. CreateNewDirDB(
  513. LPSTR DirName
  514. )
  515. {
  516. PDIRREC DirDB;
  517. AllocMem(sizeof(DIRREC) + strlen(DirName), &DirDB, MT_DIRDB);
  518. memset(DirDB, 0, sizeof(*DirDB));
  519. SigCheck(DirDB->Sig = SIG_DIRREC);
  520. CopyString(DirDB->Name, DirName, TRUE);
  521. DirDB->CheckSum = CheckSum(DirDB->Name);
  522. InitializeListHead(&DirDB->Produces);
  523. InitializeListHead(&DirDB->Consumes);
  524. return ( DirDB );
  525. }
  526. //+---------------------------------------------------------------------------
  527. //
  528. // Function: LoadDirDB
  529. //
  530. // Synopsis: Searches the database for a directory name, and if not found
  531. // creates a new DIRREC entry in the database.
  532. //
  533. // Arguments: [DirName] -- Directory to search for.
  534. //
  535. // Returns: Filled in DIRREC structure for the given directory.
  536. //
  537. // Notes: The directory will not be scanned if it wasn't in the
  538. // database. Use ScanDirectory to scan the directory,
  539. // however, note that InsertSourceDB will automatically scan
  540. // the directory only when necessary.
  541. //
  542. //----------------------------------------------------------------------------
  543. PDIRREC
  544. LoadDirDB(
  545. LPSTR DirName
  546. )
  547. {
  548. UINT i;
  549. PDIRREC DirDB, *DirDBNext;
  550. LPSTR s;
  551. AssertPathString(DirName);
  552. if (DirDB = LookupDirDB(DirName)) {
  553. return (DirDB);
  554. }
  555. if (ProbeFile(NULL, DirName) == -1) {
  556. return ( NULL );
  557. }
  558. DirDBNext = &AllDirs;
  559. while (DirDB = *DirDBNext) {
  560. DirDBNext = &DirDB->Next;
  561. }
  562. AllDirsModified = TRUE;
  563. DirDB = CreateNewDirDB(DirName);
  564. DirDB->DirFlags = DIRDB_NEW;
  565. DirDB->FindCount = 1;
  566. if (DEBUG_1) {
  567. BuildMsgRaw("LoadDirDB creating %s\n", DirDB->Name);
  568. }
  569. *DirDBNext = DirDB;
  570. return ( DirDB );
  571. }
  572. //+---------------------------------------------------------------------------
  573. //
  574. // Debug helper functions to print parts of the database.
  575. //
  576. //----------------------------------------------------------------------------
  577. #if DBG
  578. VOID
  579. PrintAllDirs(VOID)
  580. {
  581. DIRREC **ppdr, *pdr;
  582. for (ppdr = &AllDirs; (pdr = *ppdr) != NULL; ppdr = &pdr->Next) {
  583. PrintDirDB(pdr, 1|2|4);
  584. }
  585. }
  586. #endif
  587. VOID
  588. PrintFlags(FILE *pf, ULONG Flags, FLAGSTRINGS *pfs)
  589. {
  590. LPSTR p = ",";
  591. while (pfs->pszName != NULL) {
  592. if (pfs->Mask & Flags) {
  593. fprintf(pf, "%s %s", p, pfs->pszName);
  594. p = "";
  595. }
  596. pfs++;
  597. }
  598. fputs(szNewLine, pf);
  599. }
  600. BOOL
  601. PrintIncludes(FILE *pf, FILEREC *pfr, BOOL fTree)
  602. {
  603. INCLUDEREC *pir;
  604. BOOL fMatch = pfr->IncludeFilesTree == pfr->IncludeFiles;
  605. pir = fTree? pfr->IncludeFilesTree : pfr->IncludeFiles;
  606. while (pir != NULL) {
  607. LPSTR pszdir = "<No File Record>";
  608. char OpenQuote, CloseQuote;
  609. if (pir->IncFlags & INCLUDEDB_LOCAL) {
  610. OpenQuote = CloseQuote = '"';
  611. } else {
  612. OpenQuote = '<';
  613. CloseQuote = '>';
  614. }
  615. fprintf(
  616. pf,
  617. " %c#include %c%s%c",
  618. fMatch? ' ' : fTree? '+' : '-',
  619. OpenQuote,
  620. pir->Name,
  621. CloseQuote);
  622. if (pir->Version != 0) {
  623. fprintf(pf, " (v%d)", pir->Version);
  624. }
  625. if (pir->pfrCycleRoot != NULL) {
  626. fprintf(
  627. pf,
  628. " (root=%s\\%s)",
  629. pir->pfrCycleRoot->Dir->Name,
  630. pir->pfrCycleRoot->Name);
  631. }
  632. if (pir->pfrInclude != NULL) {
  633. if (pir->pfrInclude->Dir == pfr->Dir) {
  634. pszdir = ".";
  635. } else {
  636. pszdir = pir->pfrInclude->Dir->Name;
  637. }
  638. }
  639. fprintf(pf, " %s", pszdir);
  640. PrintFlags(pf, pir->IncFlags, IncludeFlags);
  641. if (pir->NextTree != pir->Next) {
  642. fMatch = FALSE;
  643. }
  644. pir = fTree? pir->NextTree : pir->Next;
  645. }
  646. return (fMatch);
  647. }
  648. VOID
  649. PrintSourceDBList(SOURCEREC *psr, int i)
  650. {
  651. TARGET_MACHINE_INFO *pMachine;
  652. pMachine = i < 0 ? TargetMachines[0] : PossibleTargetMachines[i];
  653. for ( ; psr != NULL; psr = psr->psrNext) {
  654. assert(
  655. (psr->SourceSubDirMask & ~TMIDIR_PARENT) == 0 ||
  656. pMachine->SourceSubDirMask ==
  657. (psr->SourceSubDirMask & ~TMIDIR_PARENT));
  658. BuildMsgRaw(
  659. " %s%s%s%s%s",
  660. (psr->SourceSubDirMask & TMIDIR_PARENT)? "..\\" : "",
  661. (psr->SourceSubDirMask & ~TMIDIR_PARENT)?
  662. pMachine->SourceDirectory : "",
  663. (psr->SourceSubDirMask & ~TMIDIR_PARENT)? "\\" : "",
  664. psr->pfrSource->Name,
  665. (psr->SrcFlags & SOURCEDB_PCH)?
  666. " (pch)" :
  667. (psr->SrcFlags & SOURCEDB_SOURCES_LIST) == 0?
  668. " (From exe list)" : "");
  669. PrintFlags(stderr, psr->SrcFlags, SourceFlags);
  670. }
  671. }
  672. VOID
  673. PrintFileDB(FILE *pf, FILEREC *pfr, int DetailLevel)
  674. {
  675. fprintf(pf, " File: %s", pfr->Name);
  676. if (pfr->FileFlags & FILEDB_DIR) {
  677. fprintf(pf, " (Sub-Directory)");
  678. } else
  679. if (pfr->FileFlags & (FILEDB_SOURCE | FILEDB_HEADER)) {
  680. LPSTR pszType = (pfr->FileFlags & FILEDB_SOURCE)? "Source" : "Header";
  681. if (pfr->FileFlags & FILEDB_ASM) {
  682. fprintf(pf, " (Assembler (CPP) %s File)", pszType);
  683. } else
  684. if (pfr->FileFlags & FILEDB_MASM) {
  685. fprintf(pf, " (Assembler (MASM) %s File)", pszType);
  686. } else
  687. if (pfr->FileFlags & FILEDB_RC) {
  688. fprintf(pf, " (Resource Compiler (RC) %s File)", pszType);
  689. } else
  690. if (pfr->FileFlags & FILEDB_MIDL) {
  691. fprintf(pf, " (MIDL %s File)", pszType);
  692. } else
  693. if (pfr->FileFlags & FILEDB_ASN) {
  694. fprintf(pf, " (ASN %s File)", pszType);
  695. } else
  696. if (pfr->FileFlags & FILEDB_MKTYPLIB) {
  697. fprintf(pf, " (Type Library (MkTypLib) %s File)", pszType);
  698. } else {
  699. fprintf(pf, " (C %s File)", pszType);
  700. }
  701. if ((pfr->FileFlags & FILEDB_HEADER) && pfr->Version != 0) {
  702. fprintf(pf, " (v%d)", pfr->Version);
  703. }
  704. if (pfr->GlobalSequence != 0) {
  705. fprintf(pf, " (GlobalSeq=%d)", pfr->GlobalSequence);
  706. }
  707. if (pfr->LocalSequence != 0) {
  708. fprintf(pf, " (LocalSeq=%d)", pfr->LocalSequence);
  709. }
  710. fprintf(pf, " - %u lines", pfr->SourceLines);
  711. }
  712. PrintFlags(pf, pfr->FileFlags, FileFlags);
  713. if (pfr->IncludeFiles != NULL) {
  714. BOOL fMatch;
  715. fMatch = PrintIncludes(pf, pfr, FALSE);
  716. if (pfr->IncludeFilesTree != NULL) {
  717. fprintf(pf, " IncludeTree %s\n", fMatch? "matches" : "differs:");
  718. if (!fMatch) {
  719. PrintIncludes(pf, pfr, TRUE);
  720. }
  721. }
  722. }
  723. }
  724. VOID
  725. PrintDirDB(DIRREC *pdr, int DetailLevel)
  726. {
  727. FILE *pf = stderr;
  728. FILEREC *pfr, **ppfr;
  729. if (DetailLevel & 1) {
  730. fprintf(pf, "Directory: %s", pdr->Name);
  731. if (pdr->DirFlags & DIRDB_DIRS) {
  732. fprintf(pf, " (Dirs Present)");
  733. }
  734. if (pdr->DirFlags & DIRDB_SOURCES) {
  735. fprintf(pf, " (Sources Present)");
  736. }
  737. if (pdr->DirFlags & DIRDB_MAKEFILE) {
  738. fprintf(pf, " (Makefile Present)");
  739. }
  740. PrintFlags(pf, pdr->DirFlags, DirFlags);
  741. }
  742. if (DetailLevel & 2) {
  743. if (pdr->TargetPath != NULL) {
  744. fprintf(pf, " TargetPath: %s\n", pdr->TargetPath);
  745. }
  746. if (pdr->TargetName != NULL) {
  747. fprintf(pf, " TargetName: %s\n", pdr->TargetName);
  748. }
  749. if (pdr->TargetExt != NULL) {
  750. fprintf(pf, " TargetExt: %s\n", pdr->TargetExt);
  751. }
  752. if (pdr->KernelTest != NULL) {
  753. fprintf(pf, " KernelTest: %s\n", pdr->KernelTest);
  754. }
  755. if (pdr->UserAppls != NULL) {
  756. fprintf(pf, " UserAppls: %s\n", pdr->UserAppls);
  757. }
  758. if (pdr->UserTests != NULL) {
  759. fprintf(pf, " UserTests: %s\n", pdr->UserTests);
  760. }
  761. if (pdr->PchObj != NULL) {
  762. fprintf(pf, " PchObj: %s\n", pdr->PchObj);
  763. }
  764. if (pdr->Pch != NULL) {
  765. fprintf(pf, " Pch: %s\n", pdr->Pch);
  766. }
  767. }
  768. if (DetailLevel & 4) {
  769. for (ppfr = &pdr->Files; (pfr = *ppfr) != NULL; ppfr = &pfr->Next) {
  770. PrintFileDB(pf, pfr, DetailLevel);
  771. }
  772. }
  773. }
  774. //+---------------------------------------------------------------------------
  775. //
  776. // Function: LookupFileDB
  777. //
  778. // Synopsis: Search the database for the given file.
  779. //
  780. // Arguments: [DirDB] -- Directory containing the file
  781. // [FileName] -- File to look for
  782. //
  783. // Returns: FILEREC of file if found, NULL if not.
  784. //
  785. // Notes: The file will not be added to the database if not already
  786. // there.
  787. //
  788. //----------------------------------------------------------------------------
  789. PFILEREC
  790. LookupFileDB(
  791. PDIRREC DirDB,
  792. LPSTR FileName
  793. )
  794. {
  795. PFILEREC FileDB, *FileDBNext;
  796. USHORT sum;
  797. AssertPathString(FileName);
  798. sum = CheckSum(FileName);
  799. if (DEBUG_4) {
  800. BuildMsgRaw("LookupFileDB(%s, %s) - ", DirDB->Name, FileName);
  801. }
  802. FileDBNext = &DirDB->Files;
  803. while (FileDB = *FileDBNext) {
  804. if (sum == FileDB->CheckSum && strcmp(FileName, FileDB->Name) == 0) {
  805. if (DEBUG_4) {
  806. BuildMsgRaw("success\n");
  807. }
  808. return (FileDB);
  809. }
  810. FileDBNext = &FileDB->Next;
  811. }
  812. if (DEBUG_4) {
  813. BuildMsgRaw("failure\n");
  814. }
  815. return (NULL);
  816. }
  817. //+---------------------------------------------------------------------------
  818. //
  819. // FILEDESC
  820. //
  821. // FileDesc is a table describing file names and patterns that we recognize
  822. // and handle specially. WARNING: This table is ordered so the patterns
  823. // at the front are necessarily more specific than those later on.
  824. //
  825. //----------------------------------------------------------------------------
  826. char szMakefile[] = "#";
  827. char szClang[] = "//";
  828. char szAsn[] = "--";
  829. char szMasm[] = ";";
  830. char szVBasic[] = "'";
  831. //
  832. // N.B. The first entry in the file descriptor list is an entry that is
  833. // optionally filled with the name of the target dirs file for the
  834. // first build target.
  835. //
  836. FILEDESC FileDesc[] =
  837. { { "/0dirs", szMakefile, FALSE, 0, DIRDB_DIRS},
  838. { "makefile", szMakefile, FALSE, 0, DIRDB_MAKEFILE},
  839. { "makefil0", szMakefile, FALSE, 0, DIRDB_MAKEFIL0 | DIRDB_PASS0},
  840. { "makefil1", szMakefile, FALSE, 0, DIRDB_MAKEFIL1},
  841. { "sources", szMakefile, FALSE, 0, DIRDB_SOURCES},
  842. { "dirs", szMakefile, FALSE, 0, DIRDB_DIRS},
  843. { "mydirs", szMakefile, FALSE, 0, DIRDB_DIRS},
  844. { "makefile.inc", szMakefile, FALSE, 0, 0},
  845. { "common.ver", szClang, TRUE, FILEDB_HEADER, 0},
  846. { ".rc", szClang, TRUE, FILEDB_SOURCE | FILEDB_RC, DIRDB_RESOURCE},
  847. { ".rc2", szClang, TRUE, FILEDB_SOURCE | FILEDB_RC, DIRDB_RESOURCE},
  848. { ".rcs", szClang, TRUE, FILEDB_SOURCE | FILEDB_RC, DIRDB_RESOURCE},
  849. { ".rcv", szClang, TRUE, FILEDB_SOURCE | FILEDB_RC, DIRDB_RESOURCE},
  850. { ".ver", szClang, TRUE, FILEDB_SOURCE | FILEDB_RC, DIRDB_RESOURCE},
  851. { ".c", szClang, TRUE, FILEDB_SOURCE | FILEDB_C, 0},
  852. { ".cxx", szClang, TRUE, FILEDB_SOURCE | FILEDB_C, 0},
  853. { ".cpp", szClang, TRUE, FILEDB_SOURCE | FILEDB_C, 0},
  854. { ".f", szClang, TRUE, FILEDB_SOURCE, 0},
  855. { ".p", szClang, TRUE, FILEDB_SOURCE, 0},
  856. { ".s", szClang, TRUE, FILEDB_SOURCE | FILEDB_ASM, 0},
  857. { ".asm", szMasm, TRUE, FILEDB_SOURCE | FILEDB_MASM, 0},
  858. { ".mc", szMasm, TRUE, FILEDB_SOURCE | FILEDB_RC |
  859. FILEDB_PASS0, DIRDB_PASS0},
  860. { ".idl", szClang, TRUE, FILEDB_SOURCE | FILEDB_MIDL |
  861. FILEDB_PASS0, DIRDB_PASS0},
  862. { ".asn", szAsn, TRUE, FILEDB_SOURCE | FILEDB_ASN |
  863. FILEDB_MULTIPLEPASS | FILEDB_PASS0,
  864. DIRDB_PASS0},
  865. { ".tdl", szClang, TRUE, FILEDB_SOURCE | FILEDB_MKTYPLIB | FILEDB_PASS0, 0},
  866. { ".odl", szClang, TRUE, FILEDB_SOURCE | FILEDB_MKTYPLIB | FILEDB_PASS0, 0},
  867. { ".pdl", szClang, TRUE, FILEDB_SOURCE | FILEDB_PASS0, 0},
  868. { ".h", szClang, TRUE, FILEDB_HEADER | FILEDB_C, 0},
  869. { ".hxx", szClang, TRUE, FILEDB_HEADER | FILEDB_C, 0},
  870. { ".hpp", szClang, TRUE, FILEDB_HEADER | FILEDB_C, 0},
  871. { ".hmd", szClang, TRUE, FILEDB_HEADER | FILEDB_C, 0},
  872. { ".hdl", szClang, TRUE, FILEDB_HEADER | FILEDB_C, 0},
  873. { ".inl", szClang, TRUE, FILEDB_HEADER | FILEDB_C, 0},
  874. { ".rh", szClang, TRUE, FILEDB_HEADER | FILEDB_C, 0},
  875. { ".dlg", szClang, TRUE, FILEDB_HEADER | FILEDB_RC, 0},
  876. { ".inc", szMasm, TRUE, FILEDB_HEADER | FILEDB_MASM, 0},
  877. { ".src", szClang, TRUE, FILEDB_HEADER | FILEDB_C, 0}, // see mvdm\softpc.new\obj.vdm\imlibdep.c
  878. { ".def", szClang, TRUE, FILEDB_HEADER | FILEDB_C, 0},
  879. { ".thk", szClang, TRUE, FILEDB_SOURCE | FILEDB_MULTIPLEPASS |
  880. FILEDB_PASS0, DIRDB_PASS0},
  881. { ".java", szClang, TRUE, FILEDB_SOURCE | FILEDB_JAVA, 0},
  882. { ".mof", szClang, TRUE, FILEDB_SOURCE | FILEDB_MOF |
  883. FILEDB_PASS0, DIRDB_PASS0},
  884. { ".vbp", szClang, TRUE, FILEDB_SOURCE | FILEDB_VBP, 0},
  885. { ".cs", szClang, TRUE, FILEDB_SOURCE | FILEDB_CSHARP, 0},
  886. { ".lib", szClang, TRUE, 0 ,0},
  887. { ".vb", szVBasic, TRUE, FILEDB_SOURCE | FILEDB_VB_NET, 0},
  888. // MUST BE LAST
  889. { NULL, "", FALSE, 0, 0}
  890. };
  891. //+---------------------------------------------------------------------------
  892. //
  893. // Function: MatchFileDesc
  894. //
  895. // Synopsis: Matches the given filename to an entry in FileDesc, if
  896. // possible.
  897. //
  898. // Arguments: [pszFile] -- File to match
  899. //
  900. // Returns: A FILEDESC structure. If a match was not found the data
  901. // in the FILEDESC will be empty.
  902. //
  903. //----------------------------------------------------------------------------
  904. FILEDESC *
  905. MatchFileDesc(LPSTR pszFile)
  906. {
  907. LPSTR pszExt = strrchr(pszFile, '.');
  908. FILEDESC *pfd;
  909. // treat extensionless file as .h
  910. // CONSIDER checking exactly for known files, new, memory, algorithm, vector, list, cstdio, cstdlib, etc.
  911. // CONSIDER also instead doing this where #include is parsed, to avoid doing it in
  912. // all cases (i.e., not from .rc or .c files). That'd presumably be in ScanFile.
  913. if (pszExt == NULL)
  914. pszExt = ".h";
  915. AssertPathString(pszFile);
  916. pfd = &FileDesc[0];
  917. while (pfd->pszPattern != NULL) {
  918. if (pfd->pszPattern[0] == '.') {
  919. if (pszExt != NULL && !strcmp(pszExt, pfd->pszPattern))
  920. break;
  921. } else
  922. if (!strcmp(pszFile, pfd->pszPattern))
  923. break;
  924. pfd++;
  925. }
  926. return pfd;
  927. }
  928. //+---------------------------------------------------------------------------
  929. //
  930. // Function: InsertFileDB
  931. //
  932. // Synopsis: Adds a file to the database.
  933. //
  934. // Arguments: [DirDB] -- Directory containing the file
  935. // [FileName] -- File to add
  936. // [DateTime] -- Timestamp of file
  937. // [Attr] -- File attributes (directory or file)
  938. // [FileFlags] -- FILEDB flags
  939. //
  940. // Returns: New FILEREC of file
  941. //
  942. //----------------------------------------------------------------------------
  943. PFILEREC
  944. InsertFileDB(
  945. PDIRREC DirDB,
  946. LPSTR FileName,
  947. ULONG DateTime,
  948. USHORT Attr,
  949. ULONG FileFlags)
  950. {
  951. PFILEREC FileDB, *FileDBNext;
  952. LPSTR pszCommentToEOL = NULL;
  953. AssertPathString(FileName);
  954. if (Attr & FILE_ATTRIBUTE_DIRECTORY) {
  955. if (!strcmp(FileName, ".")) {
  956. return (NULL);
  957. }
  958. if (!strcmp(FileName, "..")) {
  959. return (NULL);
  960. }
  961. assert(FileFlags == 0);
  962. FileFlags = FILEDB_DIR;
  963. } else {
  964. FILEDESC *pfd = MatchFileDesc(FileName);
  965. DirDB->DirFlags |= pfd->DirFlags;
  966. FileFlags |= pfd->FileFlags;
  967. if (!pfd->fNeedFileRec) {
  968. return (NULL);
  969. }
  970. pszCommentToEOL = pfd->pszCommentToEOL;
  971. }
  972. FileDBNext = &DirDB->Files;
  973. while ((FileDB = *FileDBNext) != NULL) {
  974. FileDBNext = &(*FileDBNext)->Next;
  975. if (strcmp(FileName, FileDB->Name) == 0) {
  976. BuildError(
  977. "%s: ignoring second instance of %s\n",
  978. DirDB->Name,
  979. FileName);
  980. return (NULL);
  981. }
  982. }
  983. AllocMem(sizeof(FILEREC) + strlen(FileName), &FileDB, MT_FILEDB);
  984. memset(FileDB, 0, sizeof(*FileDB));
  985. SigCheck(FileDB->Sig = SIG_FILEREC);
  986. CopyString(FileDB->Name, FileName, TRUE);
  987. FileDB->CheckSum = CheckSum(FileDB->Name);
  988. FileDB->DateTime = DateTime;
  989. FileDB->Attr = Attr;
  990. FileDB->Dir = DirDB;
  991. FileDB->FileFlags = FileFlags;
  992. FileDB->NewestDependency = FileDB;
  993. FileDB->pszCommentToEOL = pszCommentToEOL;
  994. if ((FileFlags & FILEDB_FILE_MISSING) == 0) {
  995. AllDirsModified = TRUE;
  996. }
  997. *FileDBNext = FileDB;
  998. return (FileDB);
  999. }
  1000. //+---------------------------------------------------------------------------
  1001. //
  1002. // Function: DeleteUnscannedFiles
  1003. //
  1004. // Synopsis: Removes unscanned files (leaving scanned files and directories)
  1005. // from the Files list of the given directory
  1006. //
  1007. // Arguments: [DirDB] -- Directory to clean up
  1008. //
  1009. //----------------------------------------------------------------------------
  1010. VOID
  1011. DeleteUnscannedFiles(
  1012. PDIRREC DirDB
  1013. )
  1014. {
  1015. PFILEREC FileDB, *FileDBNext;
  1016. FileDBNext = &DirDB->Files;
  1017. while (FileDB = *FileDBNext) {
  1018. //
  1019. // If a file has the missing flag set then it doesn't exist. But for
  1020. // it to be in the list of files it has to be listed in a SOURCES line
  1021. // (or some equivalent). This means there is a SOURCEREC somewhere
  1022. // which is pointing to the FILEREC for that file, so we don't want to
  1023. // free its memory.
  1024. //
  1025. if ( (FileDB->FileFlags & (FILEDB_SCANNED | FILEDB_FILE_MISSING | FILEDB_SOURCEREC_EXISTS)) ||
  1026. (FileDB->Attr & FILE_ATTRIBUTE_DIRECTORY) ) {
  1027. FileDBNext = &FileDB->Next;
  1028. } else {
  1029. FreeFileDB( FileDBNext );
  1030. AllDirsModified = TRUE;
  1031. }
  1032. }
  1033. }
  1034. //+---------------------------------------------------------------------------
  1035. //
  1036. // Function: InsertIncludeDB
  1037. //
  1038. // Synopsis: Inserts an include file into the database
  1039. //
  1040. // Arguments: [FileDB] -- File which includes this file
  1041. // [IncludeFileName] -- Name of include file
  1042. // [IncFlags] -- INCLUDEDB flags for this file
  1043. //
  1044. // Returns: INCLUDEREC of previously existing or new entry one.
  1045. //
  1046. //----------------------------------------------------------------------------
  1047. PINCLUDEREC
  1048. InsertIncludeDB(
  1049. PFILEREC FileDB,
  1050. LPSTR IncludeFileName,
  1051. USHORT IncFlags
  1052. )
  1053. {
  1054. PINCLUDEREC IncludeDB, *IncludeDBNext;
  1055. AssertPathString(IncludeFileName);
  1056. IncludeDBNext = &FileDB->IncludeFiles;
  1057. while (IncludeDB = *IncludeDBNext) {
  1058. AssertCleanTree(IncludeDB, FileDB); // Tree must be clean
  1059. if (!strcmp(IncludeDB->Name, IncludeFileName)) {
  1060. IncludeDB->IncFlags &= ~INCLUDEDB_GLOBAL;
  1061. IncludeDB->pfrInclude = NULL;
  1062. return (IncludeDB);
  1063. }
  1064. IncludeDBNext = &IncludeDB->Next;
  1065. }
  1066. AllocMem(
  1067. sizeof(INCLUDEREC) + strlen(IncludeFileName),
  1068. IncludeDBNext,
  1069. MT_INCLUDEDB);
  1070. IncludeDB = *IncludeDBNext;
  1071. memset(IncludeDB, 0, sizeof(*IncludeDB));
  1072. SigCheck(IncludeDB->Sig = SIG_INCLUDEREC);
  1073. IncludeDB->IncFlags = IncFlags;
  1074. CopyString(IncludeDB->Name, IncludeFileName, TRUE);
  1075. AllDirsModified = TRUE;
  1076. return (IncludeDB);
  1077. }
  1078. //+---------------------------------------------------------------------------
  1079. //
  1080. // Function: LinkToCycleRoot
  1081. //
  1082. //----------------------------------------------------------------------------
  1083. VOID
  1084. LinkToCycleRoot(INCLUDEREC *pirOrg, FILEREC *pfrCycleRoot)
  1085. {
  1086. INCLUDEREC *pir;
  1087. AllocMem(
  1088. sizeof(INCLUDEREC) + strlen(pfrCycleRoot->Name),
  1089. &pir,
  1090. MT_INCLUDEDB);
  1091. memset(pir, 0, sizeof(*pir));
  1092. SigCheck(pir->Sig = SIG_INCLUDEREC);
  1093. pir->IncFlags = INCLUDEDB_SNAPPED | INCLUDEDB_CYCLEALLOC;
  1094. pir->pfrInclude = pfrCycleRoot;
  1095. CopyString(pir->Name, pfrCycleRoot->Name, TRUE);
  1096. if (DEBUG_1) {
  1097. BuildMsgRaw(
  1098. "%x CycleAlloc %s\\%s <- %s\\%s\n",
  1099. pir,
  1100. pir->pfrInclude->Dir->Name,
  1101. pir->pfrInclude->Name,
  1102. pirOrg->pfrInclude->Dir->Name,
  1103. pirOrg->pfrInclude->Name);
  1104. }
  1105. MergeIncludeFiles(pirOrg->pfrInclude, pir, NULL);
  1106. assert((pir->IncFlags & INCLUDEDB_CYCLEORPHAN) == 0);
  1107. assert(pir->IncFlags & INCLUDEDB_CYCLEROOT);
  1108. }
  1109. //+---------------------------------------------------------------------------
  1110. //
  1111. // Function: MergeIncludeFiles
  1112. //
  1113. //----------------------------------------------------------------------------
  1114. VOID
  1115. MergeIncludeFiles(FILEREC *pfr, INCLUDEREC *pirList, FILEREC *pfrRoot)
  1116. {
  1117. INCLUDEREC *pirT;
  1118. INCLUDEREC *pir, **ppir;
  1119. while ((pirT = pirList) != NULL) {
  1120. pirList = pirList->NextTree;
  1121. pirT->NextTree = NULL;
  1122. assert(pirT->pfrInclude != NULL);
  1123. for (ppir = &pfr->IncludeFilesTree;
  1124. (pir = *ppir) != NULL;
  1125. ppir = &pir->NextTree) {
  1126. if (pirT->pfrInclude == pir->pfrInclude) {
  1127. if (pirT->IncFlags & INCLUDEDB_CYCLEROOT) {
  1128. RemoveFromCycleRoot(pirT, pfrRoot);
  1129. }
  1130. pirT->IncFlags |= INCLUDEDB_CYCLEORPHAN;
  1131. if (DEBUG_1) {
  1132. BuildMsgRaw(
  1133. "%x CycleOrphan %s\\%s <- %s\\%s\n",
  1134. pirT,
  1135. pirT->pfrInclude->Dir->Name,
  1136. pirT->pfrInclude->Name,
  1137. pfr->Dir->Name,
  1138. pfr->Name);
  1139. }
  1140. break;
  1141. }
  1142. }
  1143. if (*ppir == NULL) {
  1144. *ppir = pirT;
  1145. pirT->pfrCycleRoot = pfr;
  1146. pirT->IncFlags |= INCLUDEDB_CYCLEROOT;
  1147. if (DEBUG_1) {
  1148. BuildMsgRaw(
  1149. "%x CycleRoot %s\\%s <- %s\\%s\n",
  1150. pirT,
  1151. pirT->pfrInclude->Dir->Name,
  1152. pirT->pfrInclude->Name,
  1153. pirT->pfrCycleRoot->Dir->Name,
  1154. pirT->pfrCycleRoot->Name);
  1155. }
  1156. }
  1157. }
  1158. if (fDebug & 16) {
  1159. PrintFileDB(stderr, pfr, 2);
  1160. }
  1161. }
  1162. //+---------------------------------------------------------------------------
  1163. //
  1164. // Function: RemoveFromCycleRoot
  1165. //
  1166. //----------------------------------------------------------------------------
  1167. VOID
  1168. RemoveFromCycleRoot(INCLUDEREC *pir, FILEREC *pfrRoot)
  1169. {
  1170. INCLUDEREC **ppir;
  1171. assert(pir->pfrCycleRoot != NULL);
  1172. // if pfrRoot was passed in, the caller knows it's on pfrRoot's list,
  1173. // and is already dealing with the linked list without our help.
  1174. if (pfrRoot != NULL) {
  1175. assert((pir->IncFlags & INCLUDEDB_CYCLEALLOC) == 0);
  1176. assert(pir->pfrCycleRoot == pfrRoot);
  1177. pir->pfrCycleRoot = NULL;
  1178. pir->IncFlags &= ~INCLUDEDB_CYCLEROOT;
  1179. if (DEBUG_1) {
  1180. BuildMsgRaw(
  1181. "%x CycleUnroot %s\\%s <- %s\\%s\n",
  1182. pir,
  1183. pir->pfrInclude->Dir->Name,
  1184. pir->pfrInclude->Name,
  1185. pfrRoot->Dir->Name,
  1186. pfrRoot->Name);
  1187. }
  1188. return;
  1189. }
  1190. ppir = &pir->pfrCycleRoot->IncludeFilesTree;
  1191. while (*ppir != NULL) {
  1192. if (*ppir == pir) {
  1193. *ppir = pir->NextTree; // remove from tree list
  1194. pir->NextTree = NULL;
  1195. pir->pfrCycleRoot = NULL;
  1196. pir->IncFlags &= ~INCLUDEDB_CYCLEROOT;
  1197. return;
  1198. }
  1199. ppir = &(*ppir)->NextTree;
  1200. }
  1201. BuildError(
  1202. "%s\\%s: %x %s: not on cycle root's list\n",
  1203. pir->pfrCycleRoot->Dir->Name,
  1204. pir->pfrCycleRoot->Name,
  1205. pir,
  1206. pir->Name);
  1207. assert(pir->pfrCycleRoot == NULL); // always asserts if loop exhausted
  1208. }
  1209. //+---------------------------------------------------------------------------
  1210. //
  1211. // Function: UnsnapIncludeFiles
  1212. //
  1213. // Synopsis: Removes pointers from INCLUDEREC to the actual FILEREC of
  1214. // the include file so we can 'resnap' them.
  1215. //
  1216. // Arguments: [pfr] -- FILEREC to unsnap
  1217. // [fUnsnapGlobal] -- If TRUE, global and local includes are
  1218. // unsnapped. Otherwise, just local ones are.
  1219. //
  1220. //----------------------------------------------------------------------------
  1221. VOID
  1222. UnsnapIncludeFiles(FILEREC *pfr, BOOL fUnsnapGlobal)
  1223. {
  1224. INCLUDEREC **ppir;
  1225. INCLUDEREC *pir;
  1226. // Dynamic Tree List:
  1227. // - no cycle orphans
  1228. // - cycle roots must belong to current file record
  1229. // - cycle allocs must be freed
  1230. AssertFile(pfr);
  1231. while (pfr->IncludeFilesTree != NULL) {
  1232. pir = pfr->IncludeFilesTree; // pick up next entry
  1233. AssertInclude(pir);
  1234. pfr->IncludeFilesTree = pir->NextTree; // remove from tree list
  1235. assert((pir->IncFlags & INCLUDEDB_CYCLEORPHAN) == 0);
  1236. if (pir->IncFlags & (INCLUDEDB_CYCLEROOT | INCLUDEDB_CYCLEALLOC)) {
  1237. // unsnap the record
  1238. pir->IncFlags &= ~(INCLUDEDB_SNAPPED | INCLUDEDB_GLOBAL);
  1239. pir->pfrInclude = NULL;
  1240. pir->NextTree = NULL;
  1241. }
  1242. if (pir->IncFlags & INCLUDEDB_CYCLEROOT) {
  1243. assert(pir->pfrCycleRoot == pfr);
  1244. pir->pfrCycleRoot = NULL;
  1245. pir->IncFlags &= ~INCLUDEDB_CYCLEROOT;
  1246. }
  1247. assert(pir->pfrCycleRoot == NULL);
  1248. if (pir->IncFlags & INCLUDEDB_CYCLEALLOC) {
  1249. pir->IncFlags &= ~INCLUDEDB_CYCLEALLOC;
  1250. assert(pir->Next == NULL);
  1251. FreeIncludeDB(&pir);
  1252. }
  1253. }
  1254. // Static List:
  1255. // - no cycle allocs
  1256. // - cycle roots must be removed from a different file's Dynamic list
  1257. // - cycle orphans are nops
  1258. for (ppir = &pfr->IncludeFiles; (pir = *ppir) != NULL; ppir = &pir->Next) {
  1259. assert((pir->IncFlags & INCLUDEDB_CYCLEALLOC) == 0);
  1260. if (pir->IncFlags & INCLUDEDB_CYCLEROOT) {
  1261. assert(pir->pfrCycleRoot != pfr);
  1262. RemoveFromCycleRoot(pir, NULL);
  1263. }
  1264. pir->IncFlags &= ~INCLUDEDB_CYCLEORPHAN;
  1265. if (pir->pfrInclude != NULL &&
  1266. (fUnsnapGlobal ||
  1267. (pir->pfrInclude->Dir->DirFlags & DIRDB_GLOBAL_INCLUDES) == 0)) {
  1268. // unsnap the record
  1269. pir->IncFlags &= ~(INCLUDEDB_SNAPPED | INCLUDEDB_GLOBAL);
  1270. pir->pfrInclude = NULL;
  1271. }
  1272. pir->NextTree = NULL;
  1273. }
  1274. }
  1275. #if DBG
  1276. //+---------------------------------------------------------------------------
  1277. //
  1278. // Function: AssertCleanTree
  1279. //
  1280. // Synopsis: Enforce that no include files are snapped.
  1281. //
  1282. // Arguments: [pir] - include record to test
  1283. // [pfr] - optional containing file record
  1284. //
  1285. //----------------------------------------------------------------------------
  1286. VOID
  1287. AssertCleanTree(INCLUDEREC *pir, OPTIONAL FILEREC *pfr)
  1288. {
  1289. if (IsCleanTree(pir)) {
  1290. return;
  1291. }
  1292. if (fAssertCleanTree) {
  1293. BuildMsgRaw("\n*************************************\n");
  1294. BuildMsgRaw("Persistent Cycle: pir=%x: %s\n", pir, pir->Name);
  1295. if (pfr != NULL) {
  1296. BuildMsgRaw(" pfr=%x: %s\n", pfr, pfr->Name);
  1297. if (pfr->Dir != NULL) {
  1298. BuildMsgRaw(" pdr=%x: %s\n", pfr->Dir, pfr->Dir->Name);
  1299. }
  1300. }
  1301. if (pir->pfrInclude != NULL) {
  1302. BuildMsgRaw(" pfrInclude=%x: %s\n", pir->pfrInclude, pir->pfrInclude->Name);
  1303. if (pir->pfrInclude->Dir != NULL) {
  1304. BuildMsgRaw(" pdrInclude=%x: %s\n", pir->pfrInclude->Dir, pir->pfrInclude->Dir->Name);
  1305. }
  1306. }
  1307. BuildMsgRaw("\n*************************************\n");
  1308. fflush(stdout);
  1309. fflush(stderr);
  1310. PrintAllDirs();
  1311. BuildMsgRaw("\n*************************************\n");
  1312. fflush(stdout);
  1313. fflush(stderr);
  1314. }
  1315. assert(IsCleanTree(pir));
  1316. }
  1317. #endif
  1318. //+---------------------------------------------------------------------------
  1319. //
  1320. // Function: UnsnapAllDirectories
  1321. //
  1322. // Synopsis: Removes pointers from all INCLUDERECs to the actual FILERECs
  1323. // of include files so we can 'resnap' them.
  1324. //
  1325. // Arguments: None
  1326. //----------------------------------------------------------------------------
  1327. VOID
  1328. UnsnapAllDirectories(VOID)
  1329. {
  1330. DIRREC *pdr;
  1331. UINT i;
  1332. GlobalSequence = LocalSequence = 0;
  1333. for (pdr = AllDirs; pdr != NULL; pdr = pdr->Next) {
  1334. FILEREC *pfr;
  1335. AssertDir(pdr);
  1336. // Clear unwanted flags on each directory
  1337. pdr->DirFlags &= ~(DIRDB_SCANNED |
  1338. DIRDB_PASS0NEEDED |
  1339. DIRDB_COMPILENEEDED |
  1340. DIRDB_NEW);
  1341. pdr->CountOfFilesToCompile = 0;
  1342. pdr->SourceLinesToCompile = 0;
  1343. pdr->CountOfPassZeroFiles = 0;
  1344. pdr->PassZeroLines = 0;
  1345. // Free all source records that point to missing files, because the
  1346. // file records may be freed when rescanning directories after pass 0.
  1347. if (pdr->pds != NULL) {
  1348. for (i = 0; i < MAX_TARGET_MACHINES + 1; i++) {
  1349. SOURCEREC **ppsr;
  1350. SOURCEREC *psr;
  1351. ppsr = &pdr->pds->psrSourcesList[i];
  1352. while ((psr = *ppsr) != NULL) {
  1353. if (psr->SrcFlags & SOURCEDB_FILE_MISSING) {
  1354. FreeSourceDB(ppsr);
  1355. } else {
  1356. ppsr = &psr->psrNext;
  1357. }
  1358. }
  1359. }
  1360. }
  1361. // Clear out all snapped include files and sequence numbers
  1362. for (pfr = pdr->Files; pfr != NULL; pfr = pfr->Next) {
  1363. AssertFile(pfr);
  1364. UnsnapIncludeFiles(pfr, TRUE);
  1365. pfr->GlobalSequence = pfr->LocalSequence = 0;
  1366. }
  1367. }
  1368. }
  1369. //+---------------------------------------------------------------------------
  1370. //
  1371. // Function: MarkIncludeFileRecords
  1372. //
  1373. //----------------------------------------------------------------------------
  1374. VOID
  1375. MarkIncludeFileRecords(
  1376. PFILEREC FileDB
  1377. )
  1378. {
  1379. PINCLUDEREC IncludeDB, *IncludeDBNext;
  1380. IncludeDBNext = &FileDB->IncludeFiles;
  1381. while (IncludeDB = *IncludeDBNext) {
  1382. AssertCleanTree(IncludeDB, FileDB); // Tree must be clean
  1383. IncludeDB->pfrInclude = (PFILEREC) -1;
  1384. IncludeDBNext = &IncludeDB->Next;
  1385. }
  1386. }
  1387. //+---------------------------------------------------------------------------
  1388. //
  1389. // Function: DeleteIncludeFileRecords
  1390. //
  1391. //----------------------------------------------------------------------------
  1392. VOID
  1393. DeleteIncludeFileRecords(
  1394. PFILEREC FileDB
  1395. )
  1396. {
  1397. PINCLUDEREC IncludeDB, *IncludeDBNext;
  1398. IncludeDBNext = &FileDB->IncludeFiles;
  1399. while (IncludeDB = *IncludeDBNext) {
  1400. AssertCleanTree(IncludeDB, FileDB); // Tree must be clean
  1401. if (IncludeDB->pfrInclude == (PFILEREC) -1) {
  1402. FreeIncludeDB(IncludeDBNext);
  1403. } else {
  1404. IncludeDBNext = &IncludeDB->Next;
  1405. }
  1406. }
  1407. }
  1408. //+---------------------------------------------------------------------------
  1409. //
  1410. // Function: FindIncludeFileDB
  1411. //
  1412. // Synopsis: Find the FILEREC for an include file that our compiland
  1413. // includes.
  1414. //
  1415. // Arguments: [pfrSource] -- FILEREC of file which includes the one
  1416. // we're looking for. Might be a header.
  1417. // [pfrCompiland] -- FILEREC of ultimate source file.
  1418. // [pdrBuild] -- DIRREC of directory being built
  1419. // [pszSourceDirectory] -- Name of machine-specific dir
  1420. // [IncludeDB] -- INCLUDEDB of include file we're looking
  1421. // for.
  1422. //
  1423. // Returns: FILEREC of include file, if found.
  1424. //
  1425. //----------------------------------------------------------------------------
  1426. PFILEREC
  1427. FindIncludeFileDB(
  1428. FILEREC *pfrSource,
  1429. FILEREC *pfrCompiland,
  1430. DIRREC *pdrBuild,
  1431. LPSTR pszSourceDirectory,
  1432. INCLUDEREC *IncludeDB)
  1433. {
  1434. DIRREC *pdr;
  1435. DIRREC *pdrMachine;
  1436. FILEREC *pfr;
  1437. UINT n;
  1438. AssertFile(pfrSource);
  1439. AssertFile(pfrCompiland);
  1440. AssertDir(pfrSource->Dir);
  1441. AssertDir(pfrCompiland->Dir);
  1442. AssertDir(pdrBuild);
  1443. assert(pfrSource->Dir->FindCount >= 1);
  1444. assert(pfrCompiland->Dir->FindCount >= 1);
  1445. assert(pdrBuild->FindCount >= 1);
  1446. AssertInclude(IncludeDB);
  1447. // The rules for #include "foo.h" and #include <foo.h> are:
  1448. // - "foo.h" searches in the directory of the source file that has the
  1449. // #include statement first, then falls into the INCLUDES= directories
  1450. // - <foo.h> simply searches the INCLUDES= directories
  1451. //
  1452. // - since makefile.def *always* passes -I. -ITargetMachines[i] first,
  1453. // that has to be handled here as well.
  1454. //
  1455. // - deal with #include <sys\types> and #include "..\foo\bar.h" by
  1456. // scanning those directories, too.
  1457. n = CountIncludeDirs;
  1458. pdrMachine = FindSourceDirDB(pdrBuild->Name, pszSourceDirectory, FALSE);
  1459. // If local ("foo.h"), search the current file's directory, too.
  1460. // The compiler also will search the directory of each higher level
  1461. // file in the include hierarchy, but we won't get quite so fancy here.
  1462. // Just search the directory of the current file and of the compiland.
  1463. //
  1464. // Skip these directories if they match the current build directory or
  1465. // the machine subdirectory, because that's handled below.
  1466. if (IncludeDB->IncFlags & INCLUDEDB_LOCAL) {
  1467. if (pfrCompiland->Dir != pdrBuild &&
  1468. pfrCompiland->Dir != pdrMachine &&
  1469. pfrCompiland->Dir != pfrSource->Dir) {
  1470. AddIncludeDir(pfrCompiland->Dir, &n);
  1471. }
  1472. if (pfrSource->Dir != pdrBuild && pfrSource->Dir != pdrMachine) {
  1473. AddIncludeDir(pfrSource->Dir, &n);
  1474. }
  1475. }
  1476. // Search the current target machine subdirectory of the build directory
  1477. // -- as per makefile.def
  1478. if (pdrMachine != NULL) {
  1479. AddIncludeDir(pdrMachine, &n);
  1480. }
  1481. // Search the current build directory -- as per makefile.def.
  1482. AddIncludeDir(pdrBuild, &n);
  1483. while (n--) {
  1484. pdr = IncludeDirs[n];
  1485. if (pdr == NULL) {
  1486. continue;
  1487. }
  1488. AssertDir(pdr);
  1489. assert(pdr->FindCount >= 1);
  1490. pfr = FindSourceFileDB(pdr, IncludeDB->Name, NULL);
  1491. if (pfr != NULL) {
  1492. if (DEBUG_1) {
  1493. BuildMsgRaw(
  1494. "Found include file %s\\%s\n",
  1495. pfr->Dir->Name,
  1496. pfr->Name);
  1497. }
  1498. return (pfr);
  1499. }
  1500. }
  1501. return (NULL);
  1502. }
  1503. //+---------------------------------------------------------------------------
  1504. //
  1505. // Function: SaveMasterDB
  1506. //
  1507. // Synopsis: Save the database to disk in build.dat
  1508. //
  1509. // Arguments: (none)
  1510. //
  1511. // Returns: TRUE if successful
  1512. //
  1513. //----------------------------------------------------------------------------
  1514. BOOL
  1515. SaveMasterDB(VOID)
  1516. {
  1517. PDIRREC DirDB, *DirDBNext;
  1518. PFILEREC FileDB, *FileDBNext;
  1519. PINCLUDEREC IncludeDB, *IncludeDBNext;
  1520. FILE *fh;
  1521. if (!AllDirsModified) {
  1522. return (TRUE);
  1523. }
  1524. if (!(fh = fopen(DbMasterName, "wb"))) {
  1525. return ( FALSE );
  1526. }
  1527. setvbuf(fh, NULL, _IOFBF, 0x7000);
  1528. BuildMsg("Saving %s...", DbMasterName);
  1529. AllDirsModified = FALSE;
  1530. DirDBNext = &AllDirs;
  1531. fprintf(fh, "V %x\r\n", BUILD_VERSION);
  1532. while (DirDB = *DirDBNext) {
  1533. fprintf(fh, "D \"%s\" %x\r\n", DirDB->Name, DirDB->DirFlags);
  1534. FileDBNext = &DirDB->Files;
  1535. while (FileDB = *FileDBNext) {
  1536. if ((FileDB->FileFlags & FILEDB_FILE_MISSING) == 0) {
  1537. fprintf(
  1538. fh,
  1539. " F \"%s\" %x %x %lx %u %u\r\n",
  1540. FileDB->Name,
  1541. FileDB->FileFlags,
  1542. FileDB->Attr,
  1543. FileDB->DateTime,
  1544. FileDB->SourceLines,
  1545. FileDB->Version);
  1546. }
  1547. IncludeDBNext = &FileDB->IncludeFiles;
  1548. while (IncludeDB = *IncludeDBNext) {
  1549. fprintf(
  1550. fh,
  1551. " I \"%s\" %x %u\r\n",
  1552. IncludeDB->Name,
  1553. IncludeDB->IncFlags,
  1554. IncludeDB->Version);
  1555. IncludeDBNext= &IncludeDB->Next;
  1556. }
  1557. FileDBNext = &FileDB->Next;
  1558. }
  1559. fprintf(fh, "\r\n");
  1560. DirDBNext = &DirDB->Next;
  1561. }
  1562. fclose(fh);
  1563. BuildMsgRaw(szNewLine);
  1564. return (TRUE);
  1565. }
  1566. //+---------------------------------------------------------------------------
  1567. //
  1568. // Function: LoadMasterDB
  1569. //
  1570. // Synopsis: Load the master database from build.dat
  1571. //
  1572. // Arguments: (none)
  1573. //
  1574. //----------------------------------------------------------------------------
  1575. void
  1576. LoadMasterDB( void )
  1577. {
  1578. PDIRREC DirDB, *DirDBNext;
  1579. PFILEREC FileDB, *FileDBNext;
  1580. PINCLUDEREC IncludeDB, *IncludeDBNext;
  1581. FILE *fh;
  1582. LPSTR s;
  1583. char ch, ch2;
  1584. BOOL fFirst = TRUE;
  1585. UINT Version;
  1586. LPSTR pszerr = NULL;
  1587. AllDirs = NULL;
  1588. AllDirsModified = FALSE;
  1589. AllDirsInitialized = FALSE;
  1590. if (!SetupReadFile("", DbMasterName, ";", &fh)) {
  1591. return;
  1592. }
  1593. BuildMsg("Loading %s...", DbMasterName);
  1594. DirDBNext = &AllDirs;
  1595. FileDBNext = NULL;
  1596. IncludeDBNext = NULL;
  1597. while ((s = ReadLine(fh)) != NULL) {
  1598. ch = *s++;
  1599. if (ch == '\0') {
  1600. continue; // skip empty lines
  1601. }
  1602. ch2 = *s++; // should be a blank
  1603. if (ch2 == '\0') {
  1604. pszerr = "missing field";
  1605. break; // fail on single character lines
  1606. }
  1607. if (fFirst) {
  1608. if (ch != 'V' || ch2 != ' ' || !AToX(&s, &Version)) {
  1609. pszerr = "bad version format";
  1610. break;
  1611. }
  1612. if (Version != BUILD_VERSION) {
  1613. break;
  1614. }
  1615. fFirst = FALSE;
  1616. continue;
  1617. }
  1618. if (ch2 != ' ') {
  1619. pszerr = "bad separator";
  1620. break;
  1621. }
  1622. if (ch == 'D') {
  1623. DirDB = LoadMasterDirDB(s);
  1624. if (DirDB == NULL) {
  1625. pszerr = "Directory error";
  1626. break;
  1627. }
  1628. *DirDBNext = DirDB;
  1629. DirDBNext = &DirDB->Next;
  1630. FileDBNext = &DirDB->Files;
  1631. IncludeDBNext = NULL;
  1632. } else
  1633. if (ch == 'F' && FileDBNext != NULL) {
  1634. FileDB = LoadMasterFileDB(s);
  1635. if (FileDB == NULL) {
  1636. pszerr = "File error";
  1637. break;
  1638. }
  1639. *FileDBNext = FileDB;
  1640. FileDBNext = &FileDB->Next;
  1641. FileDB->Dir = DirDB;
  1642. IncludeDBNext = &FileDB->IncludeFiles;
  1643. } else
  1644. if (ch == 'I' && IncludeDBNext != NULL) {
  1645. IncludeDB = LoadMasterIncludeDB(s);
  1646. if (IncludeDB == NULL) {
  1647. pszerr = "Include error";
  1648. break;
  1649. }
  1650. *IncludeDBNext = IncludeDB;
  1651. IncludeDBNext = &IncludeDB->Next;
  1652. } else {
  1653. pszerr = "bad entry type";
  1654. break;
  1655. }
  1656. }
  1657. if (s != NULL) {
  1658. if (pszerr == NULL) {
  1659. BuildMsgRaw(" - old version - recomputing.\n");
  1660. } else {
  1661. BuildMsgRaw(szNewLine);
  1662. BuildError("corrupt database (%s)\n", pszerr);
  1663. }
  1664. FreeAllDirs();
  1665. } else {
  1666. BuildMsgRaw(szNewLine);
  1667. AllDirsInitialized = TRUE;
  1668. }
  1669. CloseReadFile(NULL);
  1670. return;
  1671. }
  1672. //+---------------------------------------------------------------------------
  1673. //
  1674. // Function: LoadMasterDirDB
  1675. //
  1676. // Synopsis: Load a directory entry from build.dat
  1677. //
  1678. // Arguments: [s] -- line containing text from file.
  1679. //
  1680. // Returns: DIRRECT
  1681. //
  1682. //----------------------------------------------------------------------------
  1683. PDIRREC
  1684. LoadMasterDirDB(
  1685. LPSTR s
  1686. )
  1687. {
  1688. PDIRREC DirDB;
  1689. LPSTR DirName;
  1690. ULONG MyDirFlags;
  1691. if (*s == '"') {
  1692. s++;
  1693. DirName = s;
  1694. while (*s != '"') {
  1695. s++;
  1696. }
  1697. *s++ = '\0';
  1698. } else {
  1699. DirName = s;
  1700. while (*s > ' ') {
  1701. s++;
  1702. }
  1703. }
  1704. *s++ = '\0';
  1705. if (!AToX(&s, &MyDirFlags)) {
  1706. return (NULL);
  1707. }
  1708. DirDB = CreateNewDirDB(DirName);
  1709. DirDB->DirFlags = MyDirFlags & DIRDB_DBPRESERVE;
  1710. return (DirDB);
  1711. }
  1712. //+---------------------------------------------------------------------------
  1713. //
  1714. // Function: LoadMasterFileDB
  1715. //
  1716. // Synopsis: Load a file entry from build.dat
  1717. //
  1718. // Arguments: [s] -- line containing text from file
  1719. //
  1720. // Returns: FILEREC
  1721. //
  1722. //----------------------------------------------------------------------------
  1723. PFILEREC
  1724. LoadMasterFileDB(
  1725. LPSTR s
  1726. )
  1727. {
  1728. PFILEREC FileDB;
  1729. LPSTR FileName;
  1730. ULONG Version;
  1731. ULONG MyFileFlags;
  1732. ULONG Attr;
  1733. ULONG SourceLines;
  1734. ULONG DateTime;
  1735. FILEDESC *pfd;
  1736. if (*s == '"') {
  1737. s++;
  1738. FileName = s;
  1739. while (*s != '"') {
  1740. s++;
  1741. }
  1742. *s++ = '\0';
  1743. } else {
  1744. FileName = s;
  1745. while (*s > ' ') {
  1746. s++;
  1747. }
  1748. }
  1749. *s++ = '\0';
  1750. if (!AToX(&s, &MyFileFlags) ||
  1751. !AToX(&s, &Attr) ||
  1752. !AToX(&s, &DateTime) ||
  1753. !AToD(&s, &SourceLines) ||
  1754. !AToD(&s, &Version) ||
  1755. strchr(FileName, '/') != NULL ||
  1756. strchr(FileName, '\\') != NULL) {
  1757. return (NULL);
  1758. }
  1759. AllocMem(sizeof(FILEREC) + strlen(FileName), &FileDB, MT_FILEDB);
  1760. memset(FileDB, 0, sizeof(*FileDB));
  1761. SigCheck(FileDB->Sig = SIG_FILEREC);
  1762. CopyString(FileDB->Name, FileName, TRUE);
  1763. FileDB->CheckSum = CheckSum(FileDB->Name);
  1764. FileDB->FileFlags = MyFileFlags & FILEDB_DBPRESERVE;
  1765. FileDB->Attr = (USHORT) Attr;
  1766. FileDB->DateTime = DateTime;
  1767. FileDB->Version = (USHORT) Version;
  1768. FileDB->SourceLines = SourceLines;
  1769. FileDB->NewestDependency = FileDB;
  1770. pfd = MatchFileDesc(FileDB->Name);
  1771. FileDB->pszCommentToEOL = pfd->pszCommentToEOL;
  1772. return (FileDB);
  1773. }
  1774. //+---------------------------------------------------------------------------
  1775. //
  1776. // Function: LoadMasterIncludeDB
  1777. //
  1778. // Synopsis: Loads an include file entry from build.dat
  1779. //
  1780. // Arguments: [s] -- line containing text from file.
  1781. //
  1782. // Returns: INCLUDEREC
  1783. //
  1784. //----------------------------------------------------------------------------
  1785. PINCLUDEREC
  1786. LoadMasterIncludeDB(
  1787. LPSTR s
  1788. )
  1789. {
  1790. PINCLUDEREC IncludeDB;
  1791. LPSTR FileName;
  1792. ULONG Version;
  1793. ULONG IncFlags;
  1794. if (*s == '"') {
  1795. s++;
  1796. FileName = s;
  1797. while (*s != '"') {
  1798. s++;
  1799. }
  1800. *s++ = '\0';
  1801. } else {
  1802. FileName = s;
  1803. while (*s > ' ') {
  1804. s++;
  1805. }
  1806. }
  1807. *s++ = '\0';
  1808. if (!AToX(&s, &IncFlags) || !AToD(&s, &Version)) {
  1809. return (NULL);
  1810. }
  1811. AllocMem(
  1812. sizeof(INCLUDEREC) + strlen(FileName),
  1813. &IncludeDB,
  1814. MT_INCLUDEDB);
  1815. memset(IncludeDB, 0, sizeof(*IncludeDB));
  1816. SigCheck(IncludeDB->Sig = SIG_INCLUDEREC);
  1817. IncludeDB->IncFlags = (USHORT) (IncFlags & INCLUDEDB_DBPRESERVE);
  1818. IncludeDB->Version = (USHORT) Version;
  1819. CopyString(IncludeDB->Name, FileName, TRUE);
  1820. return (IncludeDB);
  1821. }