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.

2061 lines
62 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1993.
  5. //
  6. // File: buildsrc.c
  7. //
  8. // Contents: Functions used to process SOURCES and DIRS files
  9. //
  10. // History: 16-May-89 SteveWo Created
  11. // 26-Jul-94 LyleC Split out from buildmak.c
  12. //
  13. //----------------------------------------------------------------------------
  14. #include "build.h"
  15. //
  16. // Definitions used by the macro functions
  17. //
  18. #define LPAREN '('
  19. #define RPAREN ')'
  20. // Legal character for a macro name.
  21. #define MACRO_CHAR(ch) iscsym(ch)
  22. #define CMACROMAX 1000 // maximum unique macros per sources/dirs file
  23. typedef struct _MACRO {
  24. LPSTR pszValue;
  25. UCHAR szName[1];
  26. } MACRO;
  27. MACRO *apMacro[CMACROMAX];
  28. UINT cMacro = 0;
  29. LPSTR *ppCurrentDirsFileName;
  30. DWORD StartTime;
  31. #define SOURCES_TARGETNAME 0
  32. #define SOURCES_TARGETPATH 1
  33. #define SOURCES_TARGETPATHLIB 2
  34. #define SOURCES_TARGETTYPE 3
  35. #define SOURCES_TARGETEXT 4
  36. #define SOURCES_INCLUDES 5
  37. #define SOURCES_NTTEST 6
  38. #define SOURCES_UMTYPE 7
  39. #define SOURCES_UMTEST 8
  40. #define SOURCES_OPTIONAL_UMTEST 9
  41. #define SOURCES_UMAPPL 10
  42. #define SOURCES_UMAPPLEXT 11
  43. #define SOURCES_NTTARGETFILE0 12
  44. #define SOURCES_NTTARGETFILES 13
  45. #define SOURCES_PRECOMPILED_INCLUDE 14
  46. #define SOURCES_PRECOMPILED_PCH 15
  47. #define SOURCES_PRECOMPILED_OBJ 16
  48. #define SOURCES_PRECOMPILED_TARGET 17
  49. #define SOURCES_CHICAGO_PRODUCT 18
  50. #define SOURCES_CONDITIONAL_INCLUDES 19
  51. #define SOURCES_SYNCHRONIZE_BLOCK 20
  52. #define SOURCES_SYNCHRONIZE_DRAIN 21
  53. #define SOURCES_PASS0_SOURCEDIR 22
  54. #define SOURCES_PASS0_HEADERDIR 23
  55. #define SOURCES_MIDL_UUIDDIR 24
  56. #define SOURCES_PASS0_CLIENTDIR 25
  57. #define SOURCES_PASS0_SERVERDIR 26
  58. #define SOURCES_IDLTYPE 27
  59. #define SOURCES_SOURCES_OPTIONS 28
  60. #define SOURCES_MFC_INCLUDES 29
  61. #define SOURCES_SDK_LIB_DEST 30
  62. #define SOURCES_DDK_LIB_DEST 31
  63. #define SOURCES_SDK_INC_PATH 32
  64. #define SOURCES_CRT_INC_PATH 33
  65. #define SOURCES_OAK_INC_PATH 34
  66. #define SOURCES_DDK_INC_PATH 35
  67. #define SOURCES_WDM_INC_PATH 36
  68. #define SOURCES_PRIVATE_INC_PATH 37
  69. #define SOURCES_CHECKED_ALT_DIR 38
  70. #define SOURCES_PROJECT_NAME 39
  71. #define SOURCES_PASS0_PUBLISH 40
  72. LPSTR RelevantSourcesMacros[] = {
  73. "TARGETNAME",
  74. "TARGETPATH",
  75. "TARGETPATHLIB",
  76. "TARGETTYPE",
  77. "TARGETEXT",
  78. "INCLUDES",
  79. "NTTEST",
  80. "UMTYPE",
  81. "UMTEST",
  82. "OPTIONAL_UMTEST",
  83. "UMAPPL",
  84. "UMAPPLEXT",
  85. "NTTARGETFILE0",
  86. "NTTARGETFILES",
  87. "PRECOMPILED_INCLUDE",
  88. "PRECOMPILED_PCH",
  89. "PRECOMPILED_OBJ",
  90. "PRECOMPILED_TARGET",
  91. "CHICAGO_PRODUCT",
  92. "CONDITIONAL_INCLUDES",
  93. "SYNCHRONIZE_BLOCK",
  94. "SYNCHRONIZE_DRAIN",
  95. "PASS0_SOURCEDIR",
  96. "PASS0_HEADERDIR",
  97. "MIDL_UUIDDIR",
  98. "PASS0_CLIENTDIR",
  99. "PASS0_SERVERDIR",
  100. "IDL_TYPE",
  101. "SOURCES_OPTIONS",
  102. "MFC_INCLUDES",
  103. "SDK_LIB_DEST",
  104. "DDK_LIB_DEST",
  105. "SDK_INC_PATH",
  106. "CRT_INC_PATH",
  107. "OAK_INC_PATH",
  108. "DDK_INC_PATH",
  109. "WDM_INC_PATH",
  110. "PRIVATE_INC_PATH",
  111. "CHECKED_ALT_DIR",
  112. "_PROJECT_",
  113. "PASS0_PUBLISH",
  114. NULL
  115. };
  116. #define SOURCES_MAX \
  117. (sizeof(RelevantSourcesMacros)/sizeof(RelevantSourcesMacros[0]) - 1)
  118. VOID
  119. MarkDirNames(PDIRREC DirDB, LPSTR TextLine, BOOL Required);
  120. //+---------------------------------------------------------------------------
  121. //
  122. // Function: CompressBlanks
  123. //
  124. // Synopsis: Compress multiple blank characters out of macro value, in
  125. // place.
  126. //
  127. // Arguments: [psrc] -- String to compress
  128. //
  129. // Notes: Note that tabs, CRs, continuation lines (and their line
  130. // breaks) have already been replaced with blanks.
  131. //
  132. //----------------------------------------------------------------------------
  133. VOID
  134. CompressBlanks(LPSTR psrc)
  135. {
  136. LPSTR pdst = psrc;
  137. while (*psrc == ' ') {
  138. psrc++; // skip leading macro value blanks
  139. }
  140. while (*psrc != '\0') {
  141. if (*psrc == '#') { // stop at comment
  142. break;
  143. }
  144. if ((*pdst++ = *psrc++) == ' ') {
  145. while (*psrc == ' ') {
  146. psrc++; // skip multiple blanks
  147. }
  148. }
  149. }
  150. *pdst = '\0'; // terminate the compressed copy
  151. if (*--pdst == ' ') {
  152. *pdst = '\0'; // trim trailing macro value blanks
  153. }
  154. }
  155. //+---------------------------------------------------------------------------
  156. //
  157. // Function: GetBaseDir
  158. //
  159. // Synopsis: Return the value of BASEDIR, the base NT directory, if
  160. // appropriate.
  161. //
  162. // Arguments: [pname] -- path to split
  163. //
  164. //----------------------------------------------------------------------------
  165. LPSTR
  166. GetBaseDir(LPSTR pname)
  167. {
  168. if (_stricmp("BASEDIR", pname) == 0) {
  169. return(NtRoot);
  170. }
  171. return(NULL);
  172. }
  173. //+---------------------------------------------------------------------------
  174. //
  175. // Function: FindMacro
  176. //
  177. // Synopsis: Returns the value of a given macro by name.
  178. //
  179. // Arguments: [pszName] -- Name of macro who's value is desired.
  180. //
  181. // Returns: String containing the value of the macro
  182. //
  183. //----------------------------------------------------------------------------
  184. LPSTR
  185. FindMacro(LPSTR pszName)
  186. {
  187. MACRO **ppm;
  188. for (ppm = apMacro; ppm < &apMacro[cMacro]; ppm++) {
  189. if (_stricmp(pszName, (*ppm)->szName) == 0) {
  190. return((*ppm)->pszValue);
  191. }
  192. }
  193. return(NULL);
  194. }
  195. //+---------------------------------------------------------------------------
  196. //
  197. // Function: SaveMacro
  198. //
  199. // Synopsis: Save the value of a macro
  200. //
  201. // Arguments: [pszName] -- Name of macro to save
  202. // [pszValue] -- Value of macro
  203. //
  204. // Notes: A new string must be allocated and initialized prior to
  205. // freeing the old string when updating a macro value.
  206. //
  207. //----------------------------------------------------------------------------
  208. VOID
  209. SaveMacro(LPSTR pszName, LPSTR pszValue)
  210. {
  211. MACRO **ppm;
  212. for (ppm = apMacro; ppm < &apMacro[cMacro]; ppm++) {
  213. if (_stricmp(pszName, (*ppm)->szName) == 0) {
  214. break;
  215. }
  216. }
  217. if (ppm == &apMacro[CMACROMAX]) {
  218. BuildError("Macro table full, ignoring: %s = %s\n", pszName, pszValue);
  219. return;
  220. }
  221. if (ppm == &apMacro[cMacro]) {
  222. cMacro++;
  223. AllocMem(sizeof(MACRO) + strlen(pszName), ppm, MT_MACRO);
  224. strcpy((*ppm)->szName, pszName);
  225. (*ppm)->pszValue = NULL;
  226. }
  227. MakeMacroString(&(*ppm)->pszValue, pszValue);
  228. if (DEBUG_1) {
  229. BuildMsg(
  230. "SaveMacro(%s = %s)\n",
  231. (*ppm)->szName,
  232. (*ppm)->pszValue == NULL? "NULL" : (*ppm)->pszValue);
  233. }
  234. if ((*ppm)->pszValue == NULL) {
  235. FreeMem(ppm, MT_MACRO);
  236. *ppm = apMacro[--cMacro];
  237. }
  238. }
  239. //+---------------------------------------------------------------------------
  240. //
  241. // Function: FreeMacros
  242. //
  243. // Synopsis: Free all macros
  244. //
  245. // Arguments: (none)
  246. //
  247. //----------------------------------------------------------------------------
  248. VOID
  249. FreeMacros(VOID)
  250. {
  251. MACRO **ppm;
  252. for (ppm = apMacro; ppm < &apMacro[cMacro]; ppm++) {
  253. FreeString(&(*ppm)->pszValue, MT_DIRSTRING);
  254. FreeMem(ppm, MT_MACRO);
  255. assert(*ppm == NULL);
  256. }
  257. cMacro = 0;
  258. }
  259. //+---------------------------------------------------------------------------
  260. //
  261. // Function: SplitMacro
  262. //
  263. // Synopsis: Take a string containing "MACRONAME = VALUE" and return
  264. // the target and value.
  265. //
  266. // Arguments: [pline] -- String to split and target return.
  267. //
  268. // Returns: Value of macro.
  269. //
  270. //----------------------------------------------------------------------------
  271. LPSTR
  272. SplitMacro(LPSTR *pszTarget)
  273. {
  274. LPSTR pvalue, p, pline;
  275. pvalue = NULL;
  276. pline = *pszTarget;
  277. // Quickly reject comments and ! directives.
  278. if (*pline == '#' || *pline == '!') {
  279. return NULL;
  280. }
  281. if ((p = strchr(pline, '=')) != NULL) {
  282. pvalue = p + 1; // point past old '='
  283. while (p > pline && p[-1] == ' ') {
  284. p--; // point to start of trailing blanks
  285. }
  286. // Check for missing target.
  287. if (p == pline) {
  288. return NULL;
  289. }
  290. *p = '\0'; // trim trailing blanks & '='
  291. // Perform macro substitution on target.
  292. *pszTarget = NULL;
  293. if (!MakeMacroString(pszTarget, pline)) {
  294. return NULL;
  295. }
  296. // Validate target name. If must be a non-empty string of
  297. // valid macro name characters.
  298. if (**pszTarget == 0) {
  299. FreeString(pszTarget, MT_DIRSTRING);
  300. return NULL;
  301. }
  302. for (p = *pszTarget; *p != 0; p++) {
  303. if (!MACRO_CHAR(*p)) {
  304. FreeString(pszTarget, MT_DIRSTRING);
  305. return NULL;
  306. }
  307. }
  308. CompressBlanks(pvalue);
  309. }
  310. return(pvalue);
  311. }
  312. //+---------------------------------------------------------------------------
  313. //
  314. // Function: SubstituteString
  315. //
  316. // Synopsis: Perform any macro substitution. This code was copied from the
  317. // nmake source.
  318. //
  319. // Arguments:
  320. //
  321. // Returns:
  322. //
  323. // Notes:
  324. //
  325. //----------------------------------------------------------------------------
  326. void
  327. SubstituteString(
  328. char **result,
  329. char **name,
  330. char **dest,
  331. char **end,
  332. char *source,
  333. unsigned *length
  334. )
  335. {
  336. #define ESCH '^'
  337. char *oldString, *newString;
  338. char *pEq, *pPar, *t;
  339. char *s;
  340. unsigned i;
  341. ++*name;
  342. for (pEq = *name; *pEq && *pEq != '='; pEq++)
  343. if (*pEq == ESCH)
  344. pEq++;
  345. // Did we find the '=' sign?
  346. if (*pEq != '=')
  347. printf("Error1\n");
  348. // Did the user forget the initial string?
  349. if (pEq == *name)
  350. printf("Error2\n");
  351. for (pPar = pEq; *pPar && *pPar != ')'; pPar++)
  352. if (*pPar == ESCH)
  353. pPar++;
  354. if (*pPar != ')')
  355. printf("Error3\n");
  356. oldString = (char *)malloc((UINT)((pEq - *name) + 1));
  357. if (!oldString) {
  358. BuildError("(Fatal Error) Out Of Memory: SubstituteString()\n");
  359. exit(16);
  360. }
  361. for (s = oldString, t = *name; *t != '='; *s++ = *t++)
  362. if (*t == ESCH)
  363. ++t;
  364. *s = '\0';
  365. i = strlen(oldString);
  366. newString = (char *)malloc((UINT)(pPar - pEq));
  367. if (!newString) {
  368. BuildError("(Fatal Error) Out Of Memory: SubstituteString()\n");
  369. exit(16);
  370. }
  371. for (s = newString, t++; *t != ')'; *s++ = *t++)
  372. if (*t == ESCH)
  373. ++t;
  374. *s = '\0';
  375. *name = pPar + 1;
  376. while (*source) {
  377. if ((*source == *oldString) // check for match
  378. && !strncmp(source, oldString, i)) { // copy new in for
  379. for (s = newString; *s; *(*dest)++ = *s++) // old string
  380. if (*dest == *end) {
  381. *result = realloc(*result, *length + 100);
  382. if (!*result) {
  383. BuildError("(Fatal Error) Out Of Memory: SubstituteString()\n");
  384. exit(16);
  385. }
  386. *dest = *result + *length;
  387. *length += 100;
  388. *end = *result + *length;
  389. }
  390. source += i;
  391. continue;
  392. }
  393. if (*dest == *end) {
  394. *result = realloc(*result, *length + 100);
  395. if (!*result) {
  396. BuildError("(Fatal Error) Out Of Memory: SubstituteString()\n");
  397. exit(16);
  398. }
  399. *dest = *result + *length;
  400. *length += 100;
  401. *end = *result + *length;
  402. }
  403. *(*dest)++ = *source++; // else copy 1 char
  404. }
  405. free(oldString);
  406. free(newString);
  407. }
  408. //+---------------------------------------------------------------------------
  409. //
  410. // Function: MakeMacroString
  411. //
  412. // Synopsis: Take a string, and expand any macros in it. (e.g.
  413. // "$(BASEDIR)\foobar\myfile.lib" is expanded to
  414. // "f:\nt\private\foobar\myfile.lib" if $(BASEDIR) has a value of
  415. // "f:\nt\private".
  416. //
  417. // Arguments: [pp] -- Output string
  418. // [psrc] -- Input string
  419. //
  420. // Returns:
  421. //
  422. // Notes: Any previous string value in [pp] is freed before updating it.
  423. //
  424. //----------------------------------------------------------------------------
  425. char MMSBuffer[64*1024];
  426. BOOL
  427. MakeMacroString(LPSTR *pp, LPSTR psrc)
  428. {
  429. LPSTR pname, p2, pdst, p3;
  430. int cb;
  431. char chTerminator;
  432. int cNameChars;
  433. int cChars;
  434. pdst = MMSBuffer;
  435. cb = strlen(psrc);
  436. if (cb > sizeof(MMSBuffer) - 1) {
  437. BuildError(
  438. "(Fatal Error) Buffer overflow: MakeMacroString(%s)\n",
  439. psrc);
  440. exit(16);
  441. }
  442. while ((pname = strchr(psrc, '$')) != NULL &&
  443. ((pname[1] == LPAREN &&
  444. (p2 = strchr(pname, RPAREN)) != NULL) ||
  445. (MACRO_CHAR(pname[1]) &&
  446. !MACRO_CHAR(pname[2])))) {
  447. LPSTR pszvalue;
  448. // Handle one-character non-paren macro usage.
  449. if (pname[1] == LPAREN) {
  450. // Initialize cNameChars with the number of chars to
  451. // skip to get to the first name character.
  452. cNameChars = 2;
  453. } else {
  454. p2 = pname + 2;
  455. cNameChars = 1;
  456. }
  457. chTerminator = *p2;
  458. *pname = *p2 = '\0';
  459. // copy up to macro name
  460. cChars = strlen(psrc);
  461. memcpy(pdst, psrc, cChars + 1);
  462. psrc += cChars;
  463. pdst += cChars;
  464. *pname = '$';
  465. pname += cNameChars;
  466. cNameChars += strlen(pname) + (chTerminator == RPAREN ? 1 : 0);
  467. p3 = NULL;
  468. if (chTerminator == RPAREN &&
  469. (p3 = strchr(pname, ':')) != NULL) {
  470. // macro substitution exists. ie: $(foo:old=new)
  471. *p3 = '\0';
  472. }
  473. if ((pszvalue = FindMacro(pname)) == NULL &&
  474. (pszvalue = getenv(pname)) == NULL &&
  475. (pszvalue = GetBaseDir(pname)) == NULL) {
  476. pszvalue = ""; // can't find macro name -- ignore it
  477. }
  478. if (p3) {
  479. char *pNew = malloc(10);
  480. char *pResult = pNew;
  481. char *pEnd = pNew+10;
  482. unsigned Len = 10;
  483. if (!pNew) {
  484. BuildError("(Fatal Error) Internal buffer overflow: MakeMacroString(%s[%s = %s]%s)\n",
  485. MMSBuffer,
  486. pname,
  487. pszvalue,
  488. p2 + 1);
  489. exit(16);
  490. }
  491. *p3 = ':';
  492. *p2=RPAREN;
  493. SubstituteString(&pResult, &p3, &pNew, &pEnd, pszvalue, &Len);
  494. *pNew = '\0';
  495. *p2='\0';
  496. pszvalue = pResult;
  497. }
  498. cb += strlen(pszvalue) - cNameChars;
  499. assert(cb >= 0);
  500. if (cb > sizeof(MMSBuffer) - 1) {
  501. BuildError(
  502. "(Fatal Error) Internal buffer overflow: MakeMacroString(%s[%s = %s]%s)\n",
  503. MMSBuffer,
  504. pname,
  505. pszvalue,
  506. p2 + 1);
  507. exit(16);
  508. }
  509. strcpy(pdst, pszvalue); // copy expanded value
  510. if (p3) {
  511. free(pszvalue);
  512. }
  513. pdst += strlen(pdst);
  514. *p2 = chTerminator;
  515. psrc += cNameChars;
  516. }
  517. strcpy(pdst, psrc); // copy rest of string
  518. if (pdst != MMSBuffer) {
  519. CompressBlanks(MMSBuffer);
  520. }
  521. p2 = *pp;
  522. *pp = NULL;
  523. if (MMSBuffer[0] != '\0') {
  524. MakeString(pp, MMSBuffer, TRUE, MT_DIRSTRING);
  525. }
  526. if (p2 != NULL) {
  527. FreeMem(&p2, MT_DIRSTRING);
  528. }
  529. return(MMSBuffer[0] != '\0');
  530. }
  531. //+---------------------------------------------------------------------------
  532. //
  533. // Function: SetMacroString
  534. //
  535. // Synopsis: If the two macro names are the same, store the value in that
  536. // macro
  537. //
  538. // Arguments: [pMacro1] -- Name of first macro
  539. // [pMacro2] -- Name of second macro
  540. // [pValue] -- Unexpanded value to store.
  541. // [ppValue] -- Expanded value of macro.
  542. //
  543. // Returns: BOOL
  544. //
  545. //----------------------------------------------------------------------------
  546. BOOL
  547. SetMacroString(LPSTR pMacro1, LPSTR pMacro2, LPSTR pValue, LPSTR *ppValue)
  548. {
  549. if (_stricmp(pMacro1, pMacro2) == 0) {
  550. MakeMacroString(ppValue, pValue);
  551. return(TRUE); // return TRUE even if MakeMacroString stored a NULL
  552. }
  553. return(FALSE);
  554. }
  555. //+---------------------------------------------------------------------------
  556. //
  557. // Function: SplitToken
  558. //
  559. // Synopsis: Split the string at the given separator character or space.
  560. //
  561. // Arguments: [pbuf] -- First part of split string returned here.
  562. // [chsep] -- Separator character.
  563. // [ppstr] -- Source string to split. Becomes the second half.
  564. //
  565. // Returns: TRUE if the split was successful. FALSE if it wasn't split.
  566. //
  567. // Notes: If *ppstr = "path\filename" and chsep = '\' on input, then
  568. // pbuf = "path" and *ppstr = "\filename" on output.
  569. //
  570. //----------------------------------------------------------------------------
  571. BOOL
  572. SplitToken(LPSTR pbuf, char chsep, LPSTR *ppstr)
  573. {
  574. LPSTR psrc, pdst;
  575. psrc = *ppstr;
  576. pdst = pbuf;
  577. //BuildError("SplitToken('%c', '%s') ==> ", chsep, psrc);
  578. while (*psrc == chsep || *psrc == ' ') {
  579. psrc++;
  580. }
  581. while (*psrc != '\0' && *psrc != chsep && *psrc != ' ') {
  582. *pdst = *psrc++;
  583. if (*pdst == '/') {
  584. *pdst = '\\';
  585. }
  586. pdst++;
  587. }
  588. *pdst = '\0';
  589. *ppstr = psrc;
  590. //BuildErrorRaw("('%s', '%s')\n", psrc, pbuf);
  591. return(pdst != pbuf);
  592. }
  593. //+---------------------------------------------------------------------------
  594. //
  595. // Function: CrackSources
  596. //
  597. // Synopsis: Parse the SOURCES= line in a sources file and adds those source
  598. // files to the list of sources in the DIRREC struct.
  599. //
  600. // Arguments: [pdr] -- Directory record
  601. // [pds] -- Supplemental directory information
  602. // [i] -- Which platform we're parsing
  603. //
  604. //----------------------------------------------------------------------------
  605. VOID
  606. CrackSources(
  607. DIRREC *pdr,
  608. DIRSUP *pds,
  609. int i)
  610. {
  611. LPSTR pszsubdir, plist;
  612. LPSTR pszfile, pszpath;
  613. FILEREC *pfr;
  614. DIRREC *pdrAssociate;
  615. DIRREC *pdrParent;
  616. DIRREC *pdrMachine;
  617. DIRREC *pdrParentMachine;
  618. DIRREC *pdrTarget;
  619. DIRREC **ppdr;
  620. LPSTR pszSources;
  621. char path[DB_MAX_PATH_LENGTH];
  622. TARGET_MACHINE_INFO *pMachine;
  623. if (i == 0) {
  624. pMachine = TargetMachines[0];
  625. pszSources = "SOURCES";
  626. } else {
  627. pMachine = PossibleTargetMachines[i - 1];
  628. pszSources = pMachine->SourceVariable;
  629. }
  630. pdrAssociate = pdrParent = pdrMachine = pdrParentMachine = pdrTarget = NULL;
  631. plist = pds->SourcesVariables[i];
  632. while (SplitToken(path, ' ', &plist)) {
  633. UCHAR SubDirMask, SrcFlags;
  634. SubDirMask = 0;
  635. ppdr = &pdr; // assume current directory
  636. pszsubdir = path;
  637. if (pszsubdir[0] == '.' && pszsubdir[1] == '\\') {
  638. BuildError(
  639. "%s: Ignoring current directory prefix in %s= entry: %s\n",
  640. pdr->Name,
  641. pszSources,
  642. path);
  643. pszsubdir += 2;
  644. }
  645. if (pszsubdir[0] == '.' &&
  646. pszsubdir[1] == '.' &&
  647. pszsubdir[2] == '\\') {
  648. SubDirMask = TMIDIR_PARENT;
  649. ppdr = &pdrParent; // assume parent directory
  650. pszsubdir += 3;
  651. }
  652. pszpath = path;
  653. pszfile = strchr(pszsubdir, '\\');
  654. if (pszfile == NULL) {
  655. pszfile = pszsubdir;
  656. } else {
  657. LPSTR pszSecondSlash;
  658. LPSTR pszAssociateDir;
  659. LPSTR pszMachineDir;
  660. // Check for second slash and handle $O\. If there is
  661. // no second slash, check for a machine specific directory name.
  662. // Second slashes are not legal if there's already been
  663. // a '..'.
  664. if ((SubDirMask & TMIDIR_PARENT) == 0) {
  665. pszSecondSlash = strchr(pszfile + 1, '\\');
  666. if (pszSecondSlash != NULL) {
  667. pszfile = pszSecondSlash;
  668. }
  669. } else {
  670. pszSecondSlash = NULL;
  671. }
  672. *pszfile = '\0';
  673. if (pszSecondSlash != NULL) {
  674. pszMachineDir = pMachine->ObjectDirectory[iObjectDir];
  675. pszAssociateDir = pszMachineDir;
  676. } else {
  677. pszMachineDir = pMachine->SourceDirectory;
  678. pszAssociateDir = pMachine->AssociateDirectory;
  679. }
  680. if (((_stricmp(pszsubdir, pszAssociateDir) != 0) &&
  681. (_stricmp(pszsubdir, pszMachineDir) != 0)) ||
  682. strchr(pszfile + 1, '\\') != NULL) {
  683. *pszfile = '\\';
  684. BuildError(
  685. "%s: Ignoring invalid directory prefix in %s= entry: %s\n",
  686. pdr->Name,
  687. pszSources,
  688. path);
  689. //
  690. pszpath = strrchr(path, '\\');
  691. assert(pszpath != NULL);
  692. pszpath++;
  693. SubDirMask = 0;
  694. ppdr = &pdr; // default to current direcory
  695. } else {
  696. SubDirMask |= pMachine->SourceSubDirMask;
  697. *pszfile++ = '\\';
  698. if (SubDirMask & TMIDIR_PARENT) {
  699. ppdr = &pdrParentMachine;
  700. } else if (pszSecondSlash != NULL) {
  701. // Must have matched $O.
  702. ppdr = &pdrTarget;
  703. } else {
  704. if (_stricmp(pszsubdir, pszMachineDir) != 0) {
  705. ppdr = &pdrMachine;
  706. } else {
  707. ppdr = &pdrAssociate;
  708. }
  709. }
  710. }
  711. }
  712. NewDirectory:
  713. if (*ppdr == NULL) {
  714. pfr = FindSourceFileDB(pdr, pszpath, ppdr);
  715. } else {
  716. pfr = LookupFileDB(*ppdr, pszfile);
  717. }
  718. SrcFlags = SOURCEDB_SOURCES_LIST;
  719. if ((pfr == NULL) && !fPassZero) {
  720. if (fDebug) {
  721. BuildError("%s: Missing source file: %s\n", pdr->Name, path);
  722. }
  723. if (*ppdr == NULL) {
  724. if (fDebug || pszpath == path) {
  725. BuildError(
  726. "%s: Directory does not exist: %s\n",
  727. pdr->Name,
  728. path);
  729. }
  730. // Probably an error in the subordinate sources file.
  731. // since old versions of build managed to get these entries
  732. // into the objects lists, we have to do the same...
  733. //
  734. // If ..\ prefix exists, strip it off and try again.
  735. // Else try again with the current directory.
  736. if (SubDirMask & TMIDIR_PARENT) {
  737. SubDirMask &= ~TMIDIR_PARENT; // strip off "..\\"
  738. }
  739. else {
  740. SubDirMask = 0; // use current direcory
  741. }
  742. if (SubDirMask == 0) {
  743. ppdr = &pdr; // current direcory
  744. pszpath = pszfile;
  745. }
  746. else {
  747. ppdr = &pdrMachine; // machine sub dir
  748. pszpath = pszsubdir;
  749. }
  750. goto NewDirectory;
  751. }
  752. pfr = InsertFileDB(*ppdr, pszfile, 0, 0, FILEDB_FILE_MISSING);
  753. if (pfr == NULL) {
  754. BuildError(
  755. "%s: Ignoring invalid %s= entry: %s\n",
  756. pdr->Name,
  757. pszSources,
  758. path);
  759. }
  760. }
  761. if (pfr != NULL) {
  762. AssertFile(pfr);
  763. if (SubDirMask == 0) {
  764. pfr->FileFlags |= FILEDB_OBJECTS_LIST;
  765. }
  766. if (pfr->FileFlags & FILEDB_FILE_MISSING) {
  767. SrcFlags |= SOURCEDB_FILE_MISSING;
  768. }
  769. InsertSourceDB(&pds->psrSourcesList[i], pfr, SubDirMask, SrcFlags);
  770. }
  771. }
  772. }
  773. //+---------------------------------------------------------------------------
  774. //
  775. // Function: SaveUserTests
  776. //
  777. // Synopsis: Save the value of the UMTEST macro into the DIRREC struct.
  778. //
  779. // Arguments: [DirDB] -- Dir struct to save into
  780. // [TextLine] -- String from UMTEST= line in sources file
  781. //
  782. //----------------------------------------------------------------------------
  783. VOID
  784. SaveUserTests(
  785. PDIRREC DirDB,
  786. LPSTR TextLine)
  787. {
  788. UINT i;
  789. BOOL fSave = FALSE;
  790. char name[DB_MAX_PATH_LENGTH];
  791. char buf[512];
  792. buf[0] = '\0';
  793. if (DirDB->UserTests != NULL) {
  794. strcpy(buf, DirDB->UserTests);
  795. }
  796. CopyString(TextLine, TextLine, TRUE);
  797. while (SplitToken(name, '*', &TextLine)) {
  798. for (i = 0; i < CountOptionalDirs; i++) {
  799. if (!strcmp(name, OptionalDirs[i])) {
  800. if (buf[0] != '\0') {
  801. strcat(buf, "*");
  802. DirDB->DirFlags |= DIRDB_FORCELINK; // multiple targets
  803. }
  804. strcat(buf, name);
  805. fSave = TRUE;
  806. break;
  807. }
  808. }
  809. }
  810. if (fSave) {
  811. MakeMacroString(&DirDB->UserTests, buf);
  812. DirDB->DirFlags |= DIRDB_LINKNEEDED;
  813. }
  814. }
  815. //+---------------------------------------------------------------------------
  816. //
  817. // Function: ProcessSourcesFileLine
  818. //
  819. // Synopsis: Given a line from a sources file, do the right thing.
  820. //
  821. // Arguments: [DirDB] -- Directory containing sources file
  822. // [pds] -- Supplementary info on directory
  823. // [TextLine] -- Line to process
  824. //
  825. // Returns: void
  826. //
  827. //----------------------------------------------------------------------------
  828. void
  829. ProcessSourcesFileLine(
  830. DIRREC *DirDB, // Current Directory record
  831. DIRSUP *pds, // Supplemental Directory record
  832. LPSTR TextLine, // Line to process
  833. int iTarget // Index into target machine array.
  834. )
  835. {
  836. LPSTR MacroName, p1;
  837. UINT i, iMacro;
  838. char path[DB_MAX_PATH_LENGTH];
  839. BOOL fCleanNTTargetFile0 = FALSE;
  840. LPSTR pValue; // right side of equal sign
  841. pValue = SplitMacro(&TextLine);
  842. if (pValue == NULL) {
  843. return;
  844. }
  845. // Note: TextLine is now the left side of the equal sign. See if it's interesting.
  846. //
  847. // This sets pds->SourcesVariables[0] to the value of SOURCES= if
  848. // the current line is SOURCES=...
  849. //
  850. if (SetMacroString(
  851. "SOURCES",
  852. TextLine,
  853. pValue,
  854. &pds->SourcesVariables[0])) {
  855. DirDB->DirFlags |= DIRDB_SOURCES_SET;
  856. goto SaveAndFreeMacro;
  857. }
  858. else {
  859. for (i = 0; i < MAX_TARGET_MACHINES; i++) {
  860. //
  861. // This sets pds->SourcesVariables[0] to the value of
  862. // PLAT_SOURCES= if the current line is PLAT_SOURCES=...
  863. //
  864. if (SetMacroString(
  865. PossibleTargetMachines[i]->SourceVariable,
  866. TextLine,
  867. pValue,
  868. &pds->SourcesVariables[i + 1])) {
  869. DirDB->DirFlags |= DIRDB_SOURCES_SET;
  870. goto SaveAndFreeMacro;
  871. }
  872. }
  873. }
  874. // Not a SOURCES or xxx_SOURCES macro, check against all the other interesting
  875. // macro names.
  876. iMacro = 0;
  877. while ((MacroName = RelevantSourcesMacros[iMacro]) != NULL) {
  878. if (_stricmp(TextLine, MacroName) == 0) {
  879. break;
  880. }
  881. iMacro++;
  882. }
  883. if (MacroName != NULL) { // if macro name found in list
  884. switch (iMacro) {
  885. case SOURCES_TARGETNAME:
  886. MakeMacroString(&DirDB->TargetName, pValue);
  887. break;
  888. case SOURCES_TARGETPATH:
  889. if (strcmp(pValue, "obj") == 0) {
  890. pValue = pszObjDir;
  891. }
  892. MakeMacroString(&DirDB->TargetPath, pValue);
  893. if (DirDB->TargetPath != NULL) {
  894. CreateBuildDirectory(DirDB->TargetPath);
  895. for (i = 0; i < CountTargetMachines; i++) {
  896. p1 = TargetMachines[i]->ObjectDirectory[iObjectDir];
  897. assert(strncmp(pszObjDirSlash, p1, strlen(pszObjDirSlash)) == 0);
  898. p1 += strlen(pszObjDirSlash);
  899. sprintf(path, "%s\\%s", DirDB->TargetPath, p1);
  900. CreateBuildDirectory(path);
  901. }
  902. }
  903. break;
  904. case SOURCES_TARGETPATHLIB:
  905. if (strcmp(pValue, "obj") == 0) {
  906. pValue = pszObjDir;
  907. }
  908. MakeMacroString(&DirDB->TargetPathLib, pValue);
  909. if (DirDB->TargetPathLib != NULL) {
  910. CreateBuildDirectory(DirDB->TargetPathLib);
  911. for (i = 0; i < CountTargetMachines; i++) {
  912. p1 = TargetMachines[i]->ObjectDirectory[iObjectDir];
  913. assert(strncmp(pszObjDirSlash, p1, strlen(pszObjDirSlash)) == 0);
  914. p1 += strlen(pszObjDirSlash);
  915. sprintf(path, "%s\\%s", DirDB->TargetPathLib, p1);
  916. CreateBuildDirectory(path);
  917. }
  918. }
  919. break;
  920. case SOURCES_TARGETTYPE:
  921. if (!_stricmp(pValue, "PROGRAM") || !_stricmp(pValue, "PROGLIB")) {
  922. MakeMacroString(&DirDB->TargetExt, ".exe");
  923. DirDB->DirFlags |= DIRDB_LINKNEEDED;
  924. } else if (!_stricmp(pValue, "OBJLIB")) {
  925. MakeMacroString(&DirDB->TargetExt, ".olb");
  926. DirDB->DirFlags |= DIRDB_LINKNEEDED;
  927. } else if (!_stricmp(pValue, "DRIVER") || !_stricmp(pValue, "MINIPORT")) {
  928. MakeMacroString(&DirDB->TargetExt, ".sys");
  929. DirDB->DirFlags |= DIRDB_LINKNEEDED;
  930. } else if (!_stricmp(pValue, "GDI_DRIVER")) {
  931. MakeMacroString(&DirDB->TargetExt, ".dll");
  932. DirDB->DirFlags |= DIRDB_LINKNEEDED;
  933. } else if (!_stricmp(pValue, "EXPORT_DRIVER")) {
  934. MakeMacroString(&DirDB->TargetExt, ".sys");
  935. DirDB->DirFlags |= DIRDB_LINKNEEDED;
  936. DirDB->DirFlags |= DIRDB_DLLTARGET;
  937. } else if (!_stricmp(pValue, "DYNLINK") || !_stricmp(pValue, "HAL")) {
  938. MakeMacroString(&DirDB->TargetExt, ".dll");
  939. DirDB->DirFlags |= DIRDB_LINKNEEDED;
  940. DirDB->DirFlags |= DIRDB_DLLTARGET;
  941. } else if ((!_stricmp(pValue, "LIBRARY")) || (!_stricmp(pValue, "DRIVER_LIBRARY"))) {
  942. MakeMacroString(&DirDB->TargetExt, ".lib");
  943. DirDB->DirFlags &= ~DIRDB_LINKNEEDED;
  944. } else if (!_stricmp(pValue, "UMAPPL_NOLIB")) {
  945. DirDB->DirFlags &= ~DIRDB_LINKNEEDED;
  946. } else if (!_stricmp(pValue, "NOTARGET")) {
  947. //
  948. // Used to indicate no target for a directory,
  949. // e.g. if only pass0 files are generated
  950. pds->fNoTarget = TRUE;
  951. if (!fQuicky || (fQuickZero && fFirstScan)) {
  952. DirDB->DirFlags |= DIRDB_PASS0NEEDED;
  953. }
  954. } else {
  955. BuildError( "Unsupported TARGETTYPE value - %s\n", pValue);
  956. }
  957. break;
  958. case SOURCES_TARGETEXT:
  959. {
  960. char TargetExt[_MAX_EXT] = ".";
  961. strcat(TargetExt, pValue);
  962. MakeMacroString(&DirDB->TargetExt, TargetExt);
  963. }
  964. break;
  965. case SOURCES_INCLUDES:
  966. MakeMacroString(&pds->LocalIncludePath, pValue);
  967. if (DEBUG_1) {
  968. BuildMsg(
  969. " Found local INCLUDES=%s\n",
  970. pds->LocalIncludePath);
  971. }
  972. break;
  973. case SOURCES_MFC_INCLUDES:
  974. // MFC_INCLUDES/SDK_INC/CRT_INC/OAK_INC really can't be changed
  975. // in the sources file (yet) since we've already processed the
  976. // system includes. Lay the groundwork for now.
  977. MakeMacroString((char **)&pszIncMfc, pValue);
  978. break;
  979. case SOURCES_SDK_LIB_DEST:
  980. MakeMacroString((char **)&pszSdkLibDest, pValue);
  981. break;
  982. case SOURCES_DDK_LIB_DEST:
  983. MakeMacroString((char **)&pszDdkLibDest, pValue);
  984. break;
  985. case SOURCES_SDK_INC_PATH:
  986. MakeMacroString((char **)&pszIncSdk, pValue);
  987. break;
  988. case SOURCES_CRT_INC_PATH:
  989. MakeMacroString((char **)&pszIncCrt, pValue);
  990. break;
  991. case SOURCES_OAK_INC_PATH:
  992. MakeMacroString((char **)&pszIncOak, pValue);
  993. break;
  994. case SOURCES_DDK_INC_PATH:
  995. MakeMacroString((char **)&pszIncDdk, pValue);
  996. break;
  997. case SOURCES_WDM_INC_PATH:
  998. MakeMacroString((char **)&pszIncWdm, pValue);
  999. break;
  1000. case SOURCES_PRIVATE_INC_PATH:
  1001. MakeMacroString((char **)&pszIncPri, pValue);
  1002. break;
  1003. case SOURCES_PRECOMPILED_PCH:
  1004. MakeMacroString(&DirDB->Pch, pValue);
  1005. break;
  1006. case SOURCES_PRECOMPILED_OBJ:
  1007. MakeMacroString(&DirDB->PchObj, pValue);
  1008. break;
  1009. case SOURCES_PRECOMPILED_INCLUDE:
  1010. case SOURCES_PRECOMPILED_TARGET:
  1011. {
  1012. LPSTR *ppszPath, *ppszFile, p;
  1013. if (iMacro == SOURCES_PRECOMPILED_INCLUDE) {
  1014. ppszPath = &pds->PchIncludeDir;
  1015. ppszFile = &pds->PchInclude;
  1016. } else {
  1017. ppszPath = &pds->PchTargetDir;
  1018. ppszFile = &pds->PchTarget;
  1019. }
  1020. MakeMacroString(ppszPath, ""); // free old string
  1021. if (!MakeMacroString(ppszFile, pValue)) {
  1022. break;
  1023. }
  1024. p = *ppszFile + strlen(*ppszFile);
  1025. while (p > *ppszFile && *--p != '\\')
  1026. ;
  1027. if (p > *ppszFile) {
  1028. *p = '\0';
  1029. MakeMacroString(ppszPath, *ppszFile);
  1030. MakeMacroString(ppszFile, p + 1);
  1031. }
  1032. if (DEBUG_1) {
  1033. BuildMsg(
  1034. "Precompiled header%s is %s in directory %s\n",
  1035. iMacro == SOURCES_PRECOMPILED_INCLUDE?
  1036. "" : " target",
  1037. *ppszFile,
  1038. *ppszPath != NULL?
  1039. *ppszPath : "'.'");
  1040. }
  1041. }
  1042. if (iMacro == SOURCES_PRECOMPILED_INCLUDE ||
  1043. pds->PchTargetDir == NULL) {
  1044. break;
  1045. }
  1046. EnsureDirectoriesExist(pds->PchTargetDir);
  1047. break;
  1048. case SOURCES_PASS0_HEADERDIR:
  1049. MakeMacroString(&pds->PassZeroHdrDir, pValue);
  1050. EnsureDirectoriesExist(pds->PassZeroHdrDir);
  1051. if (DEBUG_1)
  1052. {
  1053. BuildMsg("Pass Zero Header Directory is '%s'\n",
  1054. pds->PassZeroHdrDir);
  1055. }
  1056. break;
  1057. case SOURCES_PASS0_SOURCEDIR:
  1058. case SOURCES_PASS0_CLIENTDIR:
  1059. // SOURCES_PASS0_SOURCEDIR and SOURCES_PASS0_CLIENTDIR
  1060. // are mutually exclusive - enforced by makefile.def
  1061. MakeMacroString(&pds->PassZeroSrcDir1, pValue);
  1062. EnsureDirectoriesExist(pds->PassZeroSrcDir1);
  1063. if (DEBUG_1)
  1064. {
  1065. BuildMsg("Pass Zero Source/Client Directory is '%s'\n",
  1066. pds->PassZeroSrcDir1);
  1067. }
  1068. break;
  1069. case SOURCES_MIDL_UUIDDIR:
  1070. case SOURCES_PASS0_SERVERDIR:
  1071. // SOURCES_MIDL_UUIDDIR and SOURCES_PASS0_SERVERDIR
  1072. // are mutually exclusive - enforced by makefile.def
  1073. MakeMacroString(&pds->PassZeroSrcDir2, pValue);
  1074. EnsureDirectoriesExist(pds->PassZeroSrcDir2);
  1075. if (DEBUG_1)
  1076. {
  1077. BuildMsg("Midl UUID/Server Source Directory is '%s'\n",
  1078. pds->PassZeroSrcDir2);
  1079. }
  1080. break;
  1081. case SOURCES_NTTEST:
  1082. if (MakeMacroString(&DirDB->KernelTest, pValue)) {
  1083. DirDB->DirFlags |= DIRDB_LINKNEEDED;
  1084. }
  1085. break;
  1086. case SOURCES_UMTYPE:
  1087. MakeMacroString(&pds->TestType, pValue);
  1088. if (DEBUG_1) {
  1089. BuildMsg(
  1090. " Found UMTYPE=%s\n",
  1091. pds->TestType);
  1092. }
  1093. break;
  1094. case SOURCES_UMTEST:
  1095. case SOURCES_OPTIONAL_UMTEST:
  1096. SaveUserTests(DirDB, pValue);
  1097. break;
  1098. case SOURCES_UMAPPL:
  1099. if (MakeMacroString(&DirDB->UserAppls, pValue)) {
  1100. DirDB->DirFlags |= DIRDB_LINKNEEDED;
  1101. }
  1102. break;
  1103. case SOURCES_UMAPPLEXT:
  1104. if (!_stricmp(pValue, ".exe")) {
  1105. MakeMacroString(&DirDB->TargetExt, ".exe");
  1106. }
  1107. else
  1108. if (!_stricmp(pValue, ".com")) {
  1109. MakeMacroString(&DirDB->TargetExt, ".com");
  1110. }
  1111. else
  1112. if (!_stricmp(pValue, ".scr")) {
  1113. MakeMacroString(&DirDB->TargetExt, ".scr");
  1114. }
  1115. else {
  1116. BuildError(
  1117. "Unsupported UMAPPLEXT value - %s\n",
  1118. pValue);
  1119. }
  1120. break;
  1121. case SOURCES_IDLTYPE:
  1122. if (!_stricmp(pValue, "ole")) {
  1123. pds->IdlType = 0;
  1124. }
  1125. else
  1126. if (!_stricmp(pValue, "rpc")) {
  1127. pds->IdlType = 1;
  1128. }
  1129. else {
  1130. BuildError(
  1131. "Unsupported IDL_TYPE value - %s\n",
  1132. pValue);
  1133. }
  1134. break;
  1135. case SOURCES_SOURCES_OPTIONS:
  1136. fCleanNTTargetFile0 = fClean && strstr(pValue, "-c0");
  1137. break;
  1138. case SOURCES_NTTARGETFILE0:
  1139. DirDB->DirFlags |= DIRDB_TARGETFILE0;
  1140. if (fCleanNTTargetFile0) {
  1141. MakeMacroString(&DirDB->NTTargetFile0, pValue);
  1142. }
  1143. break;
  1144. case SOURCES_NTTARGETFILES:
  1145. DirDB->DirFlags |= DIRDB_TARGETFILES;
  1146. break;
  1147. case SOURCES_CHICAGO_PRODUCT:
  1148. DirDB->DirFlags |= DIRDB_CHICAGO_INCLUDES;
  1149. break;
  1150. case SOURCES_CONDITIONAL_INCLUDES:
  1151. MakeMacroString(&pds->ConditionalIncludes, pValue);
  1152. break;
  1153. case SOURCES_SYNCHRONIZE_BLOCK:
  1154. DirDB->DirFlags |= DIRDB_SYNCHRONIZE_BLOCK;
  1155. break;
  1156. case SOURCES_SYNCHRONIZE_DRAIN:
  1157. DirDB->DirFlags |= DIRDB_SYNCHRONIZE_DRAIN;
  1158. break;
  1159. case SOURCES_CHECKED_ALT_DIR:
  1160. DirDB->DirFlags |= DIRDB_CHECKED_ALT_DIR;
  1161. if (DEBUG_1) {
  1162. BuildMsg("Found CHECKED_ALT_DIR\n");
  1163. }
  1164. SetObjDir(TRUE);
  1165. if (fCheckedBuild) {
  1166. SaveMacro("_OBJ_DIR", pszObjDir);
  1167. if (iTarget < 0) {
  1168. SaveMacro("O", TargetMachines[0]->
  1169. ObjectDirectory[iObjectDir]);
  1170. } else {
  1171. SaveMacro("O",
  1172. PossibleTargetMachines[iTarget/2]->
  1173. ObjectDirectory[iObjectDir]);
  1174. }
  1175. }
  1176. break;
  1177. case SOURCES_PROJECT_NAME:
  1178. sprintf(path, "%s\\%s", NtRoot, pValue);
  1179. SaveMacro("PROJECT_ROOT", path);
  1180. break;
  1181. case SOURCES_PASS0_PUBLISH:
  1182. DirDB->DirFlags |= DIRDB_PASS0NEEDED;
  1183. break;
  1184. }
  1185. }
  1186. SaveAndFreeMacro:
  1187. SaveMacro(TextLine, pValue);
  1188. // Make sure we cleanup from the SplitMacro call at the top.
  1189. FreeString(&TextLine, MT_DIRSTRING);
  1190. }
  1191. void
  1192. ReadProjectsInfo(
  1193. DIRREC *DirDB,
  1194. DIRSUP *pds
  1195. )
  1196. {
  1197. FILE *FileHandle;
  1198. LPSTR TextLine, pBackSlash, pszProject;
  1199. BOOL Found;
  1200. char pszProjectMkPath[DB_MAX_PATH_LENGTH];
  1201. char path[DB_MAX_PATH_LENGTH];
  1202. // First load project.mk for this project.
  1203. strcpy(pszProjectMkPath, DirDB->Name);
  1204. strcpy(path, pszProjectMkPath);
  1205. strcat(path, "\\project.mk");
  1206. Found = !_access(path, 0);
  1207. while (!Found && strlen(pszProjectMkPath))
  1208. {
  1209. pBackSlash=strrchr(pszProjectMkPath, '\\');
  1210. if (pBackSlash) {
  1211. *pBackSlash = '\0';
  1212. } else {
  1213. return;
  1214. }
  1215. strcpy(path, pszProjectMkPath);
  1216. strcat(path, "\\project.mk");
  1217. Found = !_access(path, 0);
  1218. }
  1219. if (!Found) {
  1220. return;
  1221. }
  1222. if (!OpenFilePush(pszProjectMkPath, "project.mk", "#", &FileHandle)) {
  1223. return;
  1224. }
  1225. SaveMacro("_PROJECT_MK_PATH", pszProjectMkPath);
  1226. while ((TextLine = ReadLine(FileHandle)) != NULL) {
  1227. ProcessSourcesFileLine(DirDB, pds, TextLine, -1);
  1228. }
  1229. CloseReadFile(NULL);
  1230. // Load the optional myproject.mk
  1231. if (OpenFilePush(pszProjectMkPath, "myproject.mk", "#", &FileHandle)) {
  1232. while ((TextLine = ReadLine(FileHandle)) != NULL) {
  1233. ProcessSourcesFileLine(DirDB, pds, TextLine, -1);
  1234. }
  1235. CloseReadFile(NULL);
  1236. }
  1237. // Then load ntmakeenv\projects.inc to get the other magic macro names.
  1238. if (!OpenFilePush(getenv("NTMAKEENV"), "projects.inc", "#", &FileHandle)) {
  1239. return;
  1240. }
  1241. while ((TextLine = ReadLine(FileHandle)) != NULL) {
  1242. ProcessSourcesFileLine(DirDB, pds, TextLine, -1);
  1243. }
  1244. CloseReadFile(NULL);
  1245. }
  1246. //+---------------------------------------------------------------------------
  1247. //
  1248. // Function: ReadSourcesFile
  1249. //
  1250. // Synopsis: Parses the sources files (common and platform specific)
  1251. //
  1252. // Arguments: [DirDB] -- Directory containing sources file
  1253. // [pds] -- Supplementary info on directory
  1254. // [pDateTimeSources] -- Timestamp of Sources file
  1255. //
  1256. // Returns: TRUE if read successfully
  1257. //
  1258. //----------------------------------------------------------------------------
  1259. BOOL
  1260. ReadSourcesFile(DIRREC *DirDB, DIRSUP *pds, ULONG *pDateTimeSources)
  1261. {
  1262. FILE *InFileHandle;
  1263. LPSTR p, TextLine;
  1264. UINT i;
  1265. int iTarget;
  1266. ULONG DateTime;
  1267. char path[DB_MAX_PATH_LENGTH];
  1268. memset(pds, 0, sizeof(*pds));
  1269. pds->fNoTarget=FALSE;
  1270. assert(DirDB->TargetPath == NULL);
  1271. assert(DirDB->TargetPathLib == NULL);
  1272. assert(DirDB->TargetName == NULL);
  1273. assert(DirDB->TargetExt == NULL);
  1274. assert(DirDB->KernelTest == NULL);
  1275. assert(DirDB->UserAppls == NULL);
  1276. assert(DirDB->UserTests == NULL);
  1277. assert(DirDB->NTTargetFile0 == NULL);
  1278. assert(DirDB->Pch == NULL);
  1279. assert(DirDB->PchObj == NULL);
  1280. assert(cMacro == 0);
  1281. *pDateTimeSources = 0;
  1282. //
  1283. // Read the information in each of the target specific directories
  1284. // and simulate concatenation of all of the sources files.
  1285. //
  1286. // Possible sources files are read from DirDB->Name | target-source
  1287. // and DirDb->Name | ..\target-source.
  1288. //
  1289. // iTarget values, and the corresponding files processed are:
  1290. // -1 sources.
  1291. // 0 PossibleTargetMachines[0]\sources.
  1292. // 1 ..\PossibleTargetMachines[0]\sources.
  1293. // 2 PossibleTargetMachines[1]\sources.
  1294. // 3 ..\PossibleTargetMachines[1]\sources.
  1295. // 4 PossibleTargetMachines[2]\sources.
  1296. // 5 ..\PossibleTargetMachines[2]\sources.
  1297. SaveMacro("MAKEDIR", DirDB->Name);
  1298. SaveMacro("SDK_LIB_DEST", pszSdkLibDest);
  1299. SaveMacro("DDK_LIB_DEST", pszDdkLibDest);
  1300. SaveMacro("PUBLIC_INTERNAL_PATH", pszPublicInternalPath);
  1301. // Use the default architecture for now
  1302. SaveMacro("TARGET_DIRECTORY", TargetMachines[0]->SourceDirectory);
  1303. SetObjDir(FALSE);
  1304. SaveMacro("_OBJ_DIR", pszObjDir);
  1305. // Define a default CONDITIONAL_INCLUDES line to deal with the mac hdrs in windows/rpc/ole32.h.
  1306. MakeMacroString(&pds->ConditionalIncludes, "winwlm.h rpcmac.h rpcerr.h macpub.h macapi.h macname1.h macname2.h");
  1307. // Before processing the sources file, see if there's a projects.mk in the tree.
  1308. ReadProjectsInfo(DirDB, pds);
  1309. for (iTarget = -1; iTarget < 2*MAX_TARGET_MACHINES; iTarget++) {
  1310. path[0] = '\0';
  1311. if (iTarget >= 0) {
  1312. if (iTarget & 1) {
  1313. strcat(path, "..\\");
  1314. }
  1315. strcat(path, PossibleTargetMachines[iTarget/2]->SourceDirectory);
  1316. strcat(path, "\\");
  1317. }
  1318. strcat(path, "sources.");
  1319. if (!OpenFilePush(DirDB->Name, path, "#", &InFileHandle)) {
  1320. if (iTarget == -1) {
  1321. FreeMacros();
  1322. return(FALSE);
  1323. }
  1324. continue; // skip non-existent subordinate sources files
  1325. }
  1326. if (DEBUG_1) {
  1327. BuildMsg(
  1328. " Scanning%s file %s\n",
  1329. iTarget >= 0 ? " subordinate" : "",
  1330. FormatPathName(DirDB->Name, path));
  1331. }
  1332. // Update per-target macros.
  1333. if (iTarget < 0) {
  1334. SaveMacro("TARGET_DIRECTORY",
  1335. TargetMachines[0]->SourceDirectory);
  1336. SaveMacro("O", TargetMachines[0]->
  1337. ObjectDirectory[iObjectDir]);
  1338. } else {
  1339. SaveMacro("TARGET_DIRECTORY",
  1340. PossibleTargetMachines[iTarget/2]->SourceDirectory);
  1341. SaveMacro("O", PossibleTargetMachines[iTarget/2]->
  1342. ObjectDirectory[iObjectDir]);
  1343. }
  1344. DirDB->DirFlags |= DIRDB_SOURCESREAD;
  1345. while ((TextLine = ReadLine(InFileHandle)) != NULL) {
  1346. ProcessSourcesFileLine(DirDB, pds, TextLine, iTarget);
  1347. }
  1348. // Subordinate files close themselves at EOF. Timestamps
  1349. // are propagated in CloseReadFile so the primary
  1350. // file's timestamp is automatically updated.
  1351. }
  1352. // Close the primary file.
  1353. DateTime = CloseReadFile(NULL);
  1354. if (*pDateTimeSources < DateTime) {
  1355. *pDateTimeSources = DateTime; // keep newest timestamp
  1356. }
  1357. if (!pds->fNoTarget && (DirDB->TargetPath == NULL)) {
  1358. strcpy(path, "sources.");
  1359. SetupReadFile(DirDB->Name, path, "#", &InFileHandle);
  1360. BuildError(
  1361. "Unknown TARGETPATH value\n",
  1362. NULL);
  1363. CloseReadFile(NULL);
  1364. }
  1365. FreeMacros();
  1366. if (fChicagoProduct) {
  1367. DirDB->DirFlags |= DIRDB_CHICAGO_INCLUDES;
  1368. }
  1369. //
  1370. // Directory has pass0 files in it (.idl, .mc, .asn, etc), check to make
  1371. // sure they specified where the generated files should go. Default to the
  1372. // obj subdirectories if they didn't. These always need to be non-null.
  1373. //
  1374. if (!pds->PassZeroHdrDir) {
  1375. MakeString(&pds->PassZeroHdrDir, ".", TRUE, MT_DIRSTRING);
  1376. }
  1377. if (!pds->PassZeroSrcDir1) {
  1378. MakeString(&pds->PassZeroSrcDir1, ".", TRUE, MT_DIRSTRING);
  1379. }
  1380. if (!pds->PassZeroSrcDir2)
  1381. MakeString(&pds->PassZeroSrcDir2, pds->PassZeroSrcDir1, TRUE, MT_DIRSTRING);
  1382. if (DirDB->UserTests != NULL) {
  1383. _strlwr(DirDB->UserTests);
  1384. }
  1385. if (DirDB->UserAppls != NULL) {
  1386. if (DirDB->UserTests != NULL || strchr(DirDB->UserAppls, '*') != NULL) {
  1387. DirDB->DirFlags |= DIRDB_FORCELINK; // multiple targets
  1388. }
  1389. }
  1390. PostProcessSources(DirDB, pds);
  1391. if (DEBUG_1) {
  1392. PrintDirDB(DirDB, 1|2);
  1393. PrintDirSupData(pds);
  1394. PrintDirDB(DirDB, 4);
  1395. }
  1396. pds->DateTimeSources = *pDateTimeSources;
  1397. return(TRUE);
  1398. }
  1399. //+---------------------------------------------------------------------------
  1400. //
  1401. // Function: PostProcessSources
  1402. //
  1403. // Synopsis: Scan the files in the given directory and add files to the
  1404. // directory's list of source files (SOURCEREC), including PCH
  1405. // files, UMTEST files, etc.
  1406. //
  1407. // Arguments: [pdr] -- Directory to process
  1408. // [pds] -- Directory supplemental information
  1409. //
  1410. //----------------------------------------------------------------------------
  1411. void
  1412. PostProcessSources(DIRREC *pdr, DIRSUP *pds)
  1413. {
  1414. PFILEREC FileDB, *FileDBNext;
  1415. char path[DB_MAX_PATH_LENGTH];
  1416. LPSTR p, p1;
  1417. UINT i;
  1418. for (i = 0; i < MAX_TARGET_MACHINES + 1; i++) {
  1419. if (pds->SourcesVariables[i] != NULL) {
  1420. CrackSources(pdr, pds, i);
  1421. }
  1422. }
  1423. FileDBNext = &pdr->Files;
  1424. while (FileDB = *FileDBNext) {
  1425. if (pds->PchInclude && strcmp(FileDB->Name, pds->PchInclude) == 0) {
  1426. InsertSourceDB(&pds->psrSourcesList[0], FileDB, 0, SOURCEDB_PCH);
  1427. if (DEBUG_1) {
  1428. BuildMsg("Adding PCH file to Sources List: %s.\n", FileDB->Name);
  1429. }
  1430. }
  1431. if ((FileDB->FileFlags & (FILEDB_SOURCE | FILEDB_OBJECTS_LIST)) ==
  1432. FILEDB_SOURCE) {
  1433. p = FileDB->Name;
  1434. p1 = path;
  1435. while (*p != '\0' && *p != '.') {
  1436. *p1++ = *p++;
  1437. }
  1438. *p1 = '\0';
  1439. _strlwr(path);
  1440. if (pdr->KernelTest != NULL &&
  1441. !strcmp(path, pdr->KernelTest)) {
  1442. FileDB->FileFlags |= FILEDB_OBJECTS_LIST;
  1443. }
  1444. else
  1445. if (pdr->UserAppls != NULL &&
  1446. (p = strstr(pdr->UserAppls, path)) &&
  1447. (p == pdr->UserAppls || p[-1] == '*' || p[-1] == ' ')) {
  1448. FileDB->FileFlags |= FILEDB_OBJECTS_LIST;
  1449. }
  1450. else
  1451. if (pdr->UserTests != NULL &&
  1452. (p = strstr(pdr->UserTests, path)) &&
  1453. (p == pdr->UserTests || p[-1] == '*' || p[-1] == ' ')) {
  1454. FileDB->FileFlags |= FILEDB_OBJECTS_LIST;
  1455. }
  1456. if (FileDB->FileFlags & FILEDB_OBJECTS_LIST) {
  1457. InsertSourceDB(&pds->psrSourcesList[0], FileDB, 0, 0);
  1458. }
  1459. }
  1460. FileDBNext = &FileDB->Next;
  1461. }
  1462. return;
  1463. }
  1464. //+---------------------------------------------------------------------------
  1465. //
  1466. // Function: ReadDirsFile
  1467. //
  1468. // Synopsis: Parse the DIRS file
  1469. //
  1470. // Arguments: [DirDB] -- Directory to look in
  1471. //
  1472. // Returns: TRUE if parsed
  1473. //
  1474. // Notes: The existence of a file named 'mydirs' or the name of the
  1475. // target specific dirs will override the normal 'dirs' file.
  1476. //
  1477. //----------------------------------------------------------------------------
  1478. BOOL
  1479. ReadDirsFile(
  1480. PDIRREC DirDB
  1481. )
  1482. {
  1483. FILE *InFileHandle;
  1484. LPSTR TextLine, pValue;
  1485. LPSTR apszDirs[] = { "mydirs.", NULL, "dirs.", NULL };
  1486. CHAR TargetName[16];
  1487. strcpy(&TargetName[0], pszTargetDirs);
  1488. strcat(&TargetName[0], ".");
  1489. apszDirs[1] = &TargetName[0];
  1490. for (ppCurrentDirsFileName = apszDirs;
  1491. *ppCurrentDirsFileName != NULL;
  1492. ppCurrentDirsFileName++) {
  1493. if (SetupReadFile(DirDB->Name, *ppCurrentDirsFileName, "#", &InFileHandle)) {
  1494. break;
  1495. }
  1496. }
  1497. if (*ppCurrentDirsFileName == NULL) {
  1498. FreeMacros();
  1499. return(FALSE);
  1500. }
  1501. if (fFirstScan && (ppCurrentDirsFileName <= &apszDirs[1])) {
  1502. BuildMsg("Using .\\%s instead of DIRS...\n",
  1503. FormatPathName(DirDB->Name, *ppCurrentDirsFileName));
  1504. }
  1505. if (DEBUG_1) {
  1506. BuildMsg(
  1507. " Scanning file %s\n",
  1508. FormatPathName(DirDB->Name, *ppCurrentDirsFileName));
  1509. }
  1510. assert(cMacro == 0);
  1511. while ((TextLine = ReadLine(InFileHandle)) != NULL) {
  1512. if ((pValue = SplitMacro(&TextLine)) != NULL) {
  1513. SaveMacro(TextLine, pValue);
  1514. FreeString(&TextLine, MT_DIRSTRING);
  1515. }
  1516. }
  1517. CloseReadFile(NULL);
  1518. if ((pValue = FindMacro("DIRS")) != NULL) {
  1519. MarkDirNames(DirDB, pValue, TRUE);
  1520. }
  1521. if ((pValue = FindMacro("OPTIONAL_DIRS")) != NULL) {
  1522. MarkDirNames(DirDB, pValue, BuildAllOptionalDirs);
  1523. }
  1524. if ((FindMacro("SYNCHRONIZE_DRAIN")) != NULL) {
  1525. DirDB->DirFlags |= DIRDB_SYNCHRONIZE_DRAIN;
  1526. }
  1527. FreeMacros();
  1528. return( TRUE );
  1529. }
  1530. //
  1531. // Debugging and Utility Functions
  1532. //
  1533. VOID
  1534. PrintDirSupData(DIRSUP *pds)
  1535. {
  1536. int i;
  1537. if (pds->LocalIncludePath != NULL) {
  1538. BuildMsgRaw(" LocalIncludePath: %s\n", pds->LocalIncludePath);
  1539. }
  1540. if (pds->TestType != NULL) {
  1541. BuildMsgRaw(" TestType: %s\n", pds->TestType);
  1542. }
  1543. if (pds->PchIncludeDir != NULL) {
  1544. BuildMsgRaw(" PchIncludeDir: %s\n", pds->PchIncludeDir);
  1545. }
  1546. if (pds->PchInclude != NULL) {
  1547. BuildMsgRaw(" PchInclude: %s\n", pds->PchInclude);
  1548. }
  1549. if (pds->PchTargetDir != NULL) {
  1550. BuildMsgRaw(" PchTargetDir: %s\n", pds->PchTargetDir);
  1551. }
  1552. if (pds->PchTarget != NULL) {
  1553. BuildMsgRaw(" PchTarget: %s\n", pds->PchTarget);
  1554. }
  1555. if (pds->ConditionalIncludes != NULL) {
  1556. BuildMsgRaw(" ConditionalIncludes: %s\n", pds->ConditionalIncludes);
  1557. }
  1558. for (i = 0; i < MAX_TARGET_MACHINES + 1; i++) {
  1559. if (pds->SourcesVariables[i] != NULL) {
  1560. BuildMsgRaw(
  1561. " SourcesVariables[%d]: %s\n",
  1562. i,
  1563. pds->SourcesVariables[i]);
  1564. }
  1565. if (pds->psrSourcesList[i] != NULL) {
  1566. BuildMsgRaw(" SourcesList[%d]:\n", i);
  1567. PrintSourceDBList(pds->psrSourcesList[i], i - 1);
  1568. }
  1569. }
  1570. }
  1571. VOID
  1572. FreeDirSupData(DIRSUP *pds)
  1573. {
  1574. int i;
  1575. if (pds->LocalIncludePath != NULL) {
  1576. FreeMem(&pds->LocalIncludePath, MT_DIRSTRING);
  1577. }
  1578. if (pds->TestType != NULL) {
  1579. FreeMem(&pds->TestType, MT_DIRSTRING);
  1580. }
  1581. if (pds->PchInclude != NULL) {
  1582. FreeMem(&pds->PchInclude, MT_DIRSTRING);
  1583. }
  1584. if (pds->PchIncludeDir != NULL) {
  1585. FreeMem(&pds->PchIncludeDir, MT_DIRSTRING);
  1586. }
  1587. if (pds->PchTargetDir != NULL) {
  1588. FreeMem(&pds->PchTargetDir, MT_DIRSTRING);
  1589. }
  1590. if (pds->PchTarget != NULL) {
  1591. FreeMem(&pds->PchTarget, MT_DIRSTRING);
  1592. }
  1593. if (pds->ConditionalIncludes != NULL) {
  1594. FreeMem(&pds->ConditionalIncludes, MT_DIRSTRING);
  1595. }
  1596. if (pds->PassZeroHdrDir != NULL) {
  1597. FreeMem(&pds->PassZeroHdrDir, MT_DIRSTRING);
  1598. }
  1599. if (pds->PassZeroSrcDir1 != NULL) {
  1600. FreeMem(&pds->PassZeroSrcDir1, MT_DIRSTRING);
  1601. }
  1602. if (pds->PassZeroSrcDir2 != NULL) {
  1603. FreeMem(&pds->PassZeroSrcDir2, MT_DIRSTRING);
  1604. }
  1605. for (i = 0; i < MAX_TARGET_MACHINES + 1; i++) {
  1606. if (pds->SourcesVariables[i] != NULL) {
  1607. FreeMem(&pds->SourcesVariables[i], MT_DIRSTRING);
  1608. }
  1609. while (pds->psrSourcesList[i] != NULL) {
  1610. FreeSourceDB(&pds->psrSourcesList[i]);
  1611. }
  1612. }
  1613. }
  1614. VOID
  1615. FreeDirData(DIRREC *pdr)
  1616. {
  1617. if (pdr->TargetPath != NULL) {
  1618. FreeMem(&pdr->TargetPath, MT_DIRSTRING);
  1619. }
  1620. if (pdr->TargetPathLib != NULL) {
  1621. FreeMem(&pdr->TargetPathLib, MT_DIRSTRING);
  1622. }
  1623. if (pdr->TargetName != NULL) {
  1624. FreeMem(&pdr->TargetName, MT_DIRSTRING);
  1625. }
  1626. if (pdr->TargetExt != NULL) {
  1627. FreeMem(&pdr->TargetExt, MT_DIRSTRING);
  1628. }
  1629. if (pdr->KernelTest != NULL) {
  1630. FreeMem(&pdr->KernelTest, MT_DIRSTRING);
  1631. }
  1632. if (pdr->UserAppls != NULL) {
  1633. FreeMem(&pdr->UserAppls, MT_DIRSTRING);
  1634. }
  1635. if (pdr->UserTests != NULL) {
  1636. FreeMem(&pdr->UserTests, MT_DIRSTRING);
  1637. }
  1638. if (pdr->NTTargetFile0 != NULL) {
  1639. FreeMem(&pdr->NTTargetFile0, MT_DIRSTRING);
  1640. }
  1641. if (pdr->Pch != NULL) {
  1642. FreeMem(&pdr->Pch, MT_DIRSTRING);
  1643. }
  1644. if (pdr->PchObj != NULL) {
  1645. FreeMem(&pdr->PchObj, MT_DIRSTRING);
  1646. }
  1647. if (pdr->pds != NULL) {
  1648. FreeDirSupData(pdr->pds);
  1649. FreeMem(&pdr->pds, MT_DIRSUP);
  1650. pdr->pds = NULL;
  1651. }
  1652. }
  1653. //+---------------------------------------------------------------------------
  1654. //
  1655. // Function: MarkDirNames
  1656. //
  1657. // Synopsis: Parses a DIRS= or OPTIONAL_DIRS line and marks the directories
  1658. // appropriately.
  1659. //
  1660. // Arguments: [DirDB] -- Directory containing DIRS file
  1661. // [TextLine] -- DIRS= or OPTIONAL_DIRS= line
  1662. // [Required] -- Indicates if directories are optional or not.
  1663. //
  1664. //----------------------------------------------------------------------------
  1665. VOID
  1666. MarkDirNames(PDIRREC DirDB, LPSTR TextLine, BOOL Required)
  1667. {
  1668. UINT i;
  1669. LPSTR p, token;
  1670. PFILEREC FileDB, *FileDBNext;
  1671. char dirbuf[DB_MAX_PATH_LENGTH];
  1672. ULONG DirInclude;
  1673. AssertPathString(TextLine);
  1674. while (SplitToken(dirbuf, '*', &TextLine)) {
  1675. // Assume all platforms are included for this dir.
  1676. DirInclude = DIR_INCLUDE_ALL;
  1677. for (p = dirbuf; *p != '\0'; p++) {
  1678. if ( dirbuf != p && *p == '{' ) {
  1679. // An explicit include path was listed.
  1680. DirInclude = DIR_INCLUDE_NONE;
  1681. *p = '\0';
  1682. token = strtok(p+1, ",}");
  1683. while (token) {
  1684. if (!_stricmp(token, "X86") ||
  1685. !_stricmp(token, "I386") ||
  1686. !_stricmp(token, "386"))
  1687. {
  1688. DirInclude |= DIR_INCLUDE_X86;
  1689. } else if (!_stricmp(token, "32") ||
  1690. !_stricmp(token, "Win32"))
  1691. {
  1692. DirInclude |= DIR_INCLUDE_WIN32;
  1693. } else if (!_stricmp(token, "64") ||
  1694. !_stricmp(token, "Win64"))
  1695. {
  1696. DirInclude |= DIR_INCLUDE_WIN64;
  1697. } else if (!_stricmp(token, "IA64")) {
  1698. DirInclude |= DIR_INCLUDE_IA64;
  1699. } else if (!_stricmp(token, "AMD64")) {
  1700. DirInclude |= DIR_INCLUDE_AMD64;
  1701. } else if (!_stricmp(token, "RISC")) {
  1702. DirInclude |= DIR_INCLUDE_RISC;
  1703. }
  1704. token = strtok(NULL, ",}");
  1705. }
  1706. break;
  1707. } else {
  1708. if (!iscsym(*p) && *p != '.' && *p != '-' ) {
  1709. BuildError(
  1710. "%s: ignoring bad subdirectory: %s\n",
  1711. DirDB->Name,
  1712. dirbuf);
  1713. p = NULL;
  1714. break;
  1715. }
  1716. }
  1717. }
  1718. if (!(DirInclude & TargetMachines[0]->DirIncludeMask)) {
  1719. continue;
  1720. }
  1721. if (p != NULL) {
  1722. if (!Required) {
  1723. for (i = 0; i < CountOptionalDirs; i++) {
  1724. if (!strcmp(dirbuf, OptionalDirs[i])) {
  1725. OptionalDirsUsed[i] = TRUE;
  1726. break;
  1727. }
  1728. }
  1729. if (i >= CountOptionalDirs) {
  1730. p = NULL;
  1731. }
  1732. }
  1733. else {
  1734. for (i = 0; i < CountExcludeDirs; i++) {
  1735. if (!strcmp(dirbuf, ExcludeDirs[i])) {
  1736. ExcludeDirsUsed[i] = TRUE;
  1737. p = NULL;
  1738. break;
  1739. }
  1740. }
  1741. }
  1742. }
  1743. if (p != NULL) {
  1744. if ((fQuicky || fSemiQuicky) && (!fQuickZero)) {
  1745. FileDB = InsertFileDB(
  1746. DirDB,
  1747. dirbuf,
  1748. 0,
  1749. FILE_ATTRIBUTE_DIRECTORY,
  1750. 0);
  1751. if (FileDB != NULL) {
  1752. FileDB->SubDirIndex = ++DirDB->CountSubDirs;
  1753. }
  1754. }
  1755. else {
  1756. FileDBNext = &DirDB->Files;
  1757. while (FileDB = *FileDBNext) {
  1758. if (FileDB->FileFlags & FILEDB_DIR) {
  1759. if (!strcmp(dirbuf, FileDB->Name)) {
  1760. FileDB->SubDirIndex = ++DirDB->CountSubDirs;
  1761. break;
  1762. }
  1763. }
  1764. FileDBNext = &FileDB->Next;
  1765. }
  1766. if (FileDB == NULL) {
  1767. BuildError(
  1768. "%s found in %s, is not a subdirectory of %s\n",
  1769. dirbuf,
  1770. FormatPathName(DirDB->Name, *ppCurrentDirsFileName),
  1771. DirDB->Name);
  1772. }
  1773. }
  1774. }
  1775. }
  1776. }
  1777. VOID
  1778. StartElapsedTime(VOID)
  1779. {
  1780. if (fPrintElapsed && StartTime == 0) {
  1781. StartTime = GetTickCount();
  1782. }
  1783. }
  1784. VOID
  1785. PrintElapsedTime(VOID)
  1786. {
  1787. DWORD ElapsedTime;
  1788. DWORD ElapsedHours;
  1789. DWORD ElapsedMinutes;
  1790. DWORD ElapsedSeconds;
  1791. DWORD ElapsedMilliseconds;
  1792. if (fPrintElapsed) {
  1793. ElapsedTime = GetTickCount() - StartTime;
  1794. ElapsedHours = ElapsedTime/(1000 * 60 * 60);
  1795. ElapsedTime = ElapsedTime % (1000 * 60 * 60);
  1796. ElapsedMinutes = ElapsedTime/(1000 * 60);
  1797. ElapsedTime = ElapsedTime % (1000 * 60);
  1798. ElapsedSeconds = ElapsedTime/1000;
  1799. ElapsedMilliseconds = ElapsedTime % 1000;
  1800. BuildMsg(
  1801. "Elapsed time [%d:%02d:%02d.%03d]\n",
  1802. ElapsedHours,
  1803. ElapsedMinutes,
  1804. ElapsedSeconds,
  1805. ElapsedMilliseconds);
  1806. LogMsg(
  1807. "Elapsed time [%d:%02d:%02d.%03d]%s\n",
  1808. ElapsedHours,
  1809. ElapsedMinutes,
  1810. ElapsedSeconds,
  1811. ElapsedMilliseconds,
  1812. szAsterisks);
  1813. }
  1814. }