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.

2698 lines
74 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1989 - 1994
  5. //
  6. // File: buildutl.c
  7. //
  8. // Contents: Utility functions for Build.exe
  9. //
  10. // History: 16-May-89 SteveWo Created
  11. // ... See SLM log
  12. // 26-Jul-94 LyleC Cleanup/Add pass0 support
  13. // 05-Dec-00 sbonev See SD changelist 2317
  14. //
  15. //----------------------------------------------------------------------------
  16. #include "build.h"
  17. #if DBG
  18. //+---------------------------------------------------------------------------
  19. //
  20. // Memory Allocation/Deallocation functions
  21. //
  22. // These functions provide leak tracking on a debug build.
  23. //
  24. //----------------------------------------------------------------------------
  25. typedef struct _MEMHEADER {
  26. MemType mt;
  27. ULONG cbRequest;
  28. struct _MEMHEADER *pmhPrev;
  29. struct _MEMHEADER *pmhNext;
  30. } MEMHEADER;
  31. #define CBHEADER sizeof(MEMHEADER)
  32. #define CBTAIL sizeof(ULONG)
  33. char patternFree[CBTAIL] = { 'M', 'E', 'M', 'D'};
  34. char patternBusy[CBTAIL] = { 'm', 'e', 'm', 'd'};
  35. __inline MEMHEADER *
  36. GetHeader(VOID *pvblock)
  37. {
  38. return ((MEMHEADER *) (pvblock) - 1);
  39. }
  40. __inline VOID *
  41. GetBlock(MEMHEADER *pmh)
  42. {
  43. return ((VOID *) (pmh + 1));
  44. }
  45. __inline VOID
  46. FillTailBusy(LPSTR p)
  47. {
  48. memcpy(p, patternBusy, sizeof(patternBusy));
  49. }
  50. __inline VOID
  51. FillTailFree(LPSTR p)
  52. {
  53. memcpy(p, patternFree, sizeof(patternFree));
  54. }
  55. __inline BOOL
  56. CheckTail(LPSTR p)
  57. {
  58. return (memcmp(p, patternBusy, sizeof(patternBusy)) == 0);
  59. }
  60. typedef struct _MEMTAB {
  61. LPSTR pszType;
  62. ULONG cbAlloc;
  63. ULONG cAlloc;
  64. ULONG cbAllocTotal;
  65. ULONG cAllocTotal;
  66. MEMHEADER mh;
  67. } MEMTAB;
  68. ULONG cbAllocMax;
  69. ULONG cAllocMax;
  70. MEMTAB MemTab[] = {
  71. { "Totals",}, // MT_TOTALS
  72. { "Unknown",}, // MT_UNKNOWN
  73. { "ChildData",}, // MT_CHILDDATA
  74. { "CmdString",}, // MT_CMDSTRING
  75. { "DirDB",}, // MT_DIRDB
  76. { "DirSup",}, // MT_DIRSUP
  77. { "DirPath",}, // MT_DIRPATH
  78. { "DirString",}, // MT_DIRSTRING
  79. { "EventHandles",}, // MT_EVENTHANDLES
  80. { "FileDB",}, // MT_FILEDB
  81. { "FileReadBuf",}, // MT_FILEREADBUF
  82. { "FrbString",}, // MT_FRBSTRING
  83. { "IncludeDB",}, // MT_INCLUDEDB
  84. { "IoBuffer",}, // MT_IOBUFFER
  85. { "Macro",}, // MT_MACRO
  86. { "SourceDB",}, // MT_SOURCEDB
  87. { "Target",}, // MT_TARGET
  88. { "ThreadFilter",}, // MT_THREADFILTER
  89. { "ThreadHandles",}, // MT_THREADHANDLES
  90. { "ThreadState",}, // MT_THREADSTATE
  91. { "Dependency",}, // MT_DEPENDENCY
  92. { "DependencyWait",}, // MT_DEPENDENCY_WAIT
  93. { "XMLThreadState",}, // MT_XMLTHREADSTATE
  94. { "PXMLThreadState",}, // MT_PXMLTHREADSTATE
  95. };
  96. #define MT_MAX (sizeof(MemTab)/sizeof(MemTab[0]))
  97. VOID
  98. InitMem(VOID)
  99. {
  100. MEMTAB *pmt;
  101. for (pmt = MemTab; pmt < &MemTab[MT_MAX]; pmt++) {
  102. assert(pmt->cAllocTotal == 0);
  103. pmt->mh.mt = MT_INVALID;
  104. pmt->mh.pmhNext = &pmt->mh;
  105. pmt->mh.pmhPrev = &pmt->mh;
  106. }
  107. }
  108. #else
  109. #define CBHEADER 0
  110. #define CBTAIL 0
  111. #endif
  112. //+---------------------------------------------------------------------------
  113. //
  114. // Function: AllocMem
  115. //
  116. // Synopsis: Allocate memory
  117. //
  118. // Arguments: [cb] -- Requested Size
  119. // [ppv] -- [out] allocated memory
  120. // [mt] -- Type of memory being allocated (MT_XXX)
  121. //
  122. //----------------------------------------------------------------------------
  123. VOID
  124. AllocMem(size_t cb, VOID **ppv, MemType mt)
  125. {
  126. *ppv = malloc(cb + CBHEADER + CBTAIL);
  127. if (*ppv == NULL) {
  128. BuildError("(Fatal Error) malloc(%u) failed\r\n", cb);
  129. exit(16);
  130. }
  131. #if DBG
  132. {
  133. MEMTAB *pmt;
  134. MEMHEADER *pmh;
  135. pmh = *ppv;
  136. *ppv = GetBlock(pmh);
  137. if (mt >= MT_MAX) {
  138. mt = MT_UNKNOWN;
  139. }
  140. pmt = &MemTab[MT_TOTALS];
  141. if (pmt->cAllocTotal == 0) {
  142. InitMem();
  143. }
  144. pmt->cAlloc++;
  145. pmt->cAllocTotal++;
  146. pmt->cbAlloc += cb;
  147. pmt->cbAllocTotal += cb;
  148. if (cbAllocMax < pmt->cbAlloc) {
  149. cbAllocMax = pmt->cbAlloc;
  150. }
  151. if (cAllocMax < pmt->cAlloc) {
  152. cAllocMax = pmt->cAlloc;
  153. }
  154. pmt = &MemTab[mt];
  155. pmt->cAlloc++;
  156. pmt->cAllocTotal++;
  157. pmt->cbAlloc += cb;
  158. pmt->cbAllocTotal += cb;
  159. pmh->mt = mt;
  160. pmh->cbRequest = cb;
  161. pmh->pmhNext = pmt->mh.pmhNext;
  162. pmt->mh.pmhNext = pmh;
  163. pmh->pmhPrev = pmh->pmhNext->pmhPrev;
  164. pmh->pmhNext->pmhPrev = pmh;
  165. FillTailBusy((char *) *ppv + cb);
  166. if (DEBUG_4 && DEBUG_1) {
  167. BuildError("AllocMem(%d, mt=%s) -> %lx\r\n", cb, pmt->pszType, *ppv);
  168. }
  169. }
  170. #endif
  171. }
  172. //+---------------------------------------------------------------------------
  173. //
  174. // Function: FreeMem
  175. //
  176. // Synopsis: Free memory allocated by AllocMem
  177. //
  178. // Arguments: [ppv] -- Memory pointer
  179. // [mt] -- Type of memory (MT_XXX)
  180. //
  181. // Notes: Sets the memory pointer to null after freeing it.
  182. //
  183. //----------------------------------------------------------------------------
  184. VOID
  185. FreeMem(VOID **ppv, MemType mt)
  186. {
  187. assert(*ppv != NULL);
  188. #if DBG
  189. {
  190. MEMTAB *pmt;
  191. MEMHEADER *pmh;
  192. pmh = GetHeader(*ppv);
  193. if (mt == MT_DIRDB ||
  194. mt == MT_FILEDB ||
  195. mt == MT_INCLUDEDB ||
  196. mt == MT_SOURCEDB) {
  197. SigCheck(assert(((DIRREC *) (*ppv))->Sig == 0));
  198. }
  199. if (mt >= MT_MAX) {
  200. mt = MT_UNKNOWN;
  201. }
  202. pmt = &MemTab[MT_TOTALS];
  203. pmt->cAlloc--;
  204. pmt->cbAlloc -= pmh->cbRequest;
  205. pmt = &MemTab[mt];
  206. pmt->cAlloc--;
  207. pmt->cbAlloc -= pmh->cbRequest;
  208. if (DEBUG_4 && DEBUG_1) {
  209. BuildError(
  210. "FreeMem(%d, mt=%s) <- %lx\r\n",
  211. pmh->cbRequest,
  212. pmt->pszType,
  213. *ppv);
  214. }
  215. assert(CheckTail((char *) *ppv + pmh->cbRequest));
  216. FillTailFree((char *) *ppv + pmh->cbRequest);
  217. assert(mt == pmh->mt);
  218. pmh->pmhNext->pmhPrev = pmh->pmhPrev;
  219. pmh->pmhPrev->pmhNext = pmh->pmhNext;
  220. pmh->pmhNext = pmh->pmhPrev = NULL;
  221. pmh->mt = MT_INVALID;
  222. *ppv = pmh;
  223. }
  224. #endif
  225. free(*ppv);
  226. *ppv = NULL;
  227. }
  228. //+---------------------------------------------------------------------------
  229. //
  230. // Function: ReportMemoryUsage
  231. //
  232. // Synopsis: Report current memory usage (if any) on a debug build. If
  233. // called just before termination, memory leaks will be
  234. // displayed.
  235. //
  236. // Arguments: (none)
  237. //
  238. //----------------------------------------------------------------------------
  239. VOID
  240. ReportMemoryUsage(VOID)
  241. {
  242. #if DBG
  243. MEMTAB *pmt;
  244. UINT i;
  245. if (DEBUG_1) {
  246. BuildErrorRaw(
  247. "Maximum memory usage: %5lx bytes in %4lx blocks\r\n",
  248. cbAllocMax,
  249. cAllocMax);
  250. for (pmt = MemTab; pmt < &MemTab[MT_MAX]; pmt++) {
  251. BuildErrorRaw(
  252. "%5lx bytes in %4lx blocks, %5lx bytes in %4lx blocks Total (%s)\r\n",
  253. pmt->cbAlloc,
  254. pmt->cAlloc,
  255. pmt->cbAllocTotal,
  256. pmt->cAllocTotal,
  257. pmt->pszType);
  258. }
  259. }
  260. FreeMem(&BigBuf, MT_IOBUFFER);
  261. if (fDebug & 8) {
  262. PrintAllDirs();
  263. }
  264. FreeAllDirs();
  265. if (DEBUG_1 || MemTab[MT_TOTALS].cbAlloc != 0) {
  266. BuildErrorRaw(szNewLine);
  267. if (MemTab[MT_TOTALS].cbAlloc != 0) {
  268. BuildError("Internal memory leaks detected:\r\n");
  269. }
  270. for (pmt = MemTab; pmt < &MemTab[MT_MAX]; pmt++) {
  271. BuildErrorRaw(
  272. "%5lx bytes in %4lx blocks, %5lx bytes in %4lx blocks Total (%s)\r\n",
  273. pmt->cbAlloc,
  274. pmt->cAlloc,
  275. pmt->cbAllocTotal,
  276. pmt->cAllocTotal,
  277. pmt->pszType);
  278. }
  279. }
  280. #endif
  281. }
  282. //+---------------------------------------------------------------------------
  283. //
  284. // Function: MyOpenFile
  285. //
  286. // Synopsis: Open a file
  287. //
  288. //----------------------------------------------------------------------------
  289. BOOL
  290. MyOpenFile(
  291. LPSTR DirName,
  292. LPSTR FileName,
  293. LPSTR Access,
  294. FILE **ppf,
  295. BOOL BufferedIO)
  296. {
  297. char path[ DB_MAX_PATH_LENGTH * 2 + 1] = {0}; // ensure we have enough space for "DirName" + "\\" + "FileName"
  298. if (DirName == NULL || DirName[0] == '\0') {
  299. strncpy( path, FileName, sizeof(path) - 1 );
  300. } else {
  301. _snprintf( path, sizeof(path) - 1, "%s\\%s", DirName, FileName );
  302. }
  303. *ppf = fopen( path, Access );
  304. if (*ppf == NULL) {
  305. if (*Access == 'w') {
  306. BuildError("%s: create file failed\r\n", path);
  307. }
  308. return (FALSE);
  309. }
  310. if (!BufferedIO) {
  311. setvbuf(*ppf, NULL, _IONBF, 0); // Clear buffering on the stream.
  312. }
  313. return (TRUE);
  314. }
  315. typedef struct _FILEREADBUF {
  316. struct _FILEREADBUF *pfrbNext;
  317. LPSTR pszFile;
  318. LPSTR pbBuffer;
  319. LPSTR pbNext;
  320. size_t cbBuf;
  321. size_t cbBuffer;
  322. size_t cbTotal;
  323. size_t cbFile;
  324. USHORT cLine;
  325. USHORT cNull;
  326. ULONG DateTime;
  327. FILE *pf;
  328. LPSTR pszCommentToEOL;
  329. size_t cbCommentToEOL;
  330. BOOLEAN fEof;
  331. BOOLEAN fOpen;
  332. BOOLEAN fMakefile;
  333. } FILEREADBUF;
  334. static FILEREADBUF Frb;
  335. char achzeros[16];
  336. //+---------------------------------------------------------------------------
  337. //
  338. // Function: OpenFilePush
  339. //
  340. //----------------------------------------------------------------------------
  341. BOOL
  342. OpenFilePush(
  343. LPSTR pszdir,
  344. LPSTR pszfile,
  345. LPSTR pszCommentToEOL,
  346. FILE **ppf
  347. )
  348. {
  349. FILEREADBUF *pfrb;
  350. if (Frb.fOpen) {
  351. AllocMem(sizeof(*pfrb), &pfrb, MT_FILEREADBUF);
  352. memcpy(pfrb, &Frb, sizeof(*pfrb));
  353. memset(&Frb, 0, sizeof(Frb));
  354. Frb.pfrbNext = pfrb;
  355. } else {
  356. pfrb = NULL;
  357. }
  358. if (!SetupReadFile(
  359. pszdir,
  360. pszfile,
  361. pszCommentToEOL,
  362. ppf)) {
  363. if (pfrb != NULL) {
  364. memcpy(&Frb, pfrb, sizeof(*pfrb));
  365. FreeMem(&pfrb, MT_FILEREADBUF);
  366. }
  367. return FALSE;
  368. }
  369. return TRUE;
  370. }
  371. //+---------------------------------------------------------------------------
  372. //
  373. // Function: ReadFilePush
  374. //
  375. //----------------------------------------------------------------------------
  376. LPSTR
  377. ReadFilePush(LPSTR pszfile)
  378. {
  379. FILE *pf;
  380. assert(Frb.fOpen);
  381. OpenFilePush(IsFullPath(pszfile) ? "" : Frb.pszFile, pszfile,
  382. Frb.pszCommentToEOL, &pf);
  383. return (ReadLine(Frb.pf));
  384. }
  385. //+---------------------------------------------------------------------------
  386. //
  387. // Function: ReadFilePop
  388. //
  389. //----------------------------------------------------------------------------
  390. LPSTR
  391. ReadFilePop(VOID)
  392. {
  393. if (Frb.pfrbNext == NULL) {
  394. return (NULL);
  395. }
  396. CloseReadFile(NULL);
  397. return (ReadLine(Frb.pf));
  398. }
  399. //+---------------------------------------------------------------------------
  400. //
  401. // Function: ReadBuf
  402. //
  403. //----------------------------------------------------------------------------
  404. BOOL
  405. ReadBuf(FILE *pf)
  406. {
  407. LPSTR p, p2;
  408. assert(pf == Frb.pf);
  409. assert(!Frb.fEof);
  410. Frb.pbNext = Frb.pbBuffer;
  411. Frb.cbBuf = fread(Frb.pbBuffer, 1, Frb.cbBuffer - 1, Frb.pf);
  412. if (Frb.cbTotal == 0 &&
  413. Frb.cbBuf > sizeof(achzeros) &&
  414. memcmp(Frb.pbBuffer, achzeros, sizeof(achzeros)) == 0) {
  415. BuildError("ignoring binary file\r\n");
  416. Frb.fEof = TRUE;
  417. return (FALSE);
  418. }
  419. p = &Frb.pbBuffer[Frb.cbBuf - 1];
  420. if (Frb.cbTotal + Frb.cbBuf < Frb.cbFile) {
  421. do {
  422. while (p > Frb.pbBuffer && *p != '\n') {
  423. p--;
  424. }
  425. p2 = p; // save end of last complete line
  426. if (p > Frb.pbBuffer && *p == '\n') {
  427. p--;
  428. if (p > Frb.pbBuffer && *p == '\r') {
  429. p--;
  430. }
  431. while (p > Frb.pbBuffer && (*p == '\t' || *p == ' ')) {
  432. p--;
  433. }
  434. }
  435. } while (*p == '\\');
  436. if (p == Frb.pbBuffer) {
  437. BuildError("(Fatal Error) too many continuation lines\r\n");
  438. exit(8);
  439. }
  440. p = p2; // restore end of last complete line
  441. Frb.cbBuf = p - Frb.pbBuffer + 1;
  442. } else {
  443. Frb.fEof = TRUE; // no more to read
  444. }
  445. p[1] = '\0';
  446. Frb.cbTotal += Frb.cbBuf;
  447. return (TRUE);
  448. }
  449. //+---------------------------------------------------------------------------
  450. //
  451. // Function: IsNmakeInclude
  452. //
  453. //----------------------------------------------------------------------------
  454. LPSTR
  455. IsNmakeInclude(LPSTR pinc)
  456. {
  457. static char szInclude[] = "include";
  458. LPSTR pnew, p;
  459. while (*pinc == ' ') {
  460. pinc++;
  461. }
  462. if (_strnicmp(pinc, szInclude, sizeof(szInclude) - 1) == 0 &&
  463. pinc[sizeof(szInclude) - 1] == ' ') {
  464. pnew = NULL;
  465. pinc += sizeof(szInclude);
  466. while (*pinc == ' ') {
  467. pinc++;
  468. }
  469. if (MakeMacroString(&pnew, pinc)) {
  470. p = strchr(pnew, ' ');
  471. if (p != NULL) {
  472. *p = '\0';
  473. }
  474. return (pnew);
  475. }
  476. }
  477. return (NULL);
  478. }
  479. //+---------------------------------------------------------------------------
  480. //
  481. // Function: ReadLine
  482. //
  483. // Synopsis: Read a line from the input file.
  484. //
  485. // Arguments: [pf] -- File to read from
  486. //
  487. // Returns: Line read from file
  488. //
  489. // Notes: ReadLine returns a canonical line from the input file.
  490. // This involves:
  491. //
  492. // 1) Converting tab to spaces. Various editors/users change
  493. // tabbing.
  494. // 2) Uniformly terminate lines. Some editors drop CR in
  495. // CRLF or add extras.
  496. // 3) Handle file-type-specific continuations.
  497. //
  498. //----------------------------------------------------------------------------
  499. LPSTR
  500. ReadLine(FILE *pf)
  501. {
  502. LPSTR p, pend, pline;
  503. LPSTR pcont;
  504. LPSTR pcomment;
  505. UCHAR chComment0 = Frb.pszCommentToEOL[0];
  506. BOOL fInComment, fWhiteSpace;
  507. assert(pf == Frb.pf || (pf != NULL && Frb.pfrbNext != NULL));
  508. if (Frb.cbBuf == 0) {
  509. if (Frb.fEof) {
  510. return (ReadFilePop());
  511. }
  512. if (fseek(Frb.pf, Frb.cbTotal, SEEK_SET) == -1) {
  513. return (ReadFilePop());
  514. }
  515. if (!ReadBuf(Frb.pf)) {
  516. return (ReadFilePop());
  517. }
  518. }
  519. pline = p = Frb.pbNext;
  520. pend = &p[Frb.cbBuf];
  521. pcont = NULL;
  522. pcomment = NULL;
  523. // scan through line forward
  524. fInComment = FALSE;
  525. while (p < pend) {
  526. switch (*p) {
  527. case ' ':
  528. case '\t':
  529. case '\r':
  530. *p = ' ';
  531. break;
  532. case '\\':
  533. pcont = p; // remember continuation character
  534. break;
  535. case '\n': // Are we at an end of line?
  536. case '\0':
  537. if (*p == '\n') {
  538. Frb.cLine++;
  539. }
  540. if (fInComment) {
  541. memset(pcomment, ' ', p-pcomment-1);
  542. fInComment = FALSE;
  543. }
  544. if (pcont == NULL) {
  545. goto eol; // bail out if single line
  546. } // else combine multiple lines...
  547. *pcont = ' '; // remove continuation char
  548. pcont = NULL; // eat only one line per continuation
  549. *p = ' '; // join the lines with blanks
  550. break;
  551. default:
  552. // See if the character we're examining begins the
  553. // comment-to-EOL string.
  554. if (*p == chComment0 &&
  555. !strncmp(p, Frb.pszCommentToEOL, Frb.cbCommentToEOL) &&
  556. !fInComment) {
  557. fInComment = TRUE;
  558. pcomment = p;
  559. }
  560. pcont = NULL; // not a continuation character
  561. break;
  562. }
  563. p++;
  564. }
  565. eol:
  566. assert(Frb.cbBuf >= p - Frb.pbNext);
  567. Frb.cbBuf -= p - Frb.pbNext;
  568. Frb.pbNext = p;
  569. if (pcont != NULL) {
  570. *pcont = ' '; // file ended with backslash...
  571. }
  572. assert(*p == '\0' || *p == '\n');
  573. if (p < pend) {
  574. if (*p == '\0') {
  575. if (Frb.cNull++ == 0) {
  576. BuildError("null byte at offset %lx\r\n",
  577. Frb.cbTotal - Frb.cbBuf + p - Frb.pbNext);
  578. }
  579. }
  580. *p = '\0'; // terminate line
  581. assert(Frb.cbBuf >= 1);
  582. Frb.cbBuf--; // account for newline (or null)
  583. Frb.pbNext++;
  584. } else {
  585. assert(p == pend && *p == '\0');
  586. if (*pline == 'Z' - 64 && p == &pline[1] && Frb.cbBuf == 0) {
  587. pline = NULL; // found CTL-Z at end of file
  588. } else {
  589. // BuildError( "last line incomplete\r\n");
  590. }
  591. }
  592. fWhiteSpace = FALSE;
  593. if (pline != NULL) {
  594. while (*pline == ' ') {
  595. pline++; // skip leading whitespace
  596. fWhiteSpace = TRUE;
  597. }
  598. if (*p != '\0') {
  599. BuildError( "\"*p != '\\0'\" at offset %lx\r\n",
  600. Frb.cbTotal - Frb.cbBuf + p - Frb.pbNext);
  601. BuildError(
  602. "pline=%x(%s) p=%x(%s)\r\n",
  603. pline,
  604. pline,
  605. p,
  606. p,
  607. Frb.cbTotal - Frb.cbBuf + p - Frb.pbNext);
  608. }
  609. assert(*p == '\0');
  610. while (p > pline && *--p == ' ') {
  611. *p = '\0'; // truncate trailing whitespace
  612. }
  613. }
  614. if (pline == NULL) {
  615. return (ReadFilePop());
  616. }
  617. if (Frb.fMakefile && !fWhiteSpace && *pline == '!') {
  618. p = IsNmakeInclude(pline + 1);
  619. if (p != NULL) {
  620. if (Frb.fMakefile && DEBUG_4) {
  621. BuildError("!include(%s)\r\n", p);
  622. }
  623. pline = ReadFilePush(p);
  624. FreeMem(&p, MT_DIRSTRING);
  625. }
  626. }
  627. return (pline);
  628. }
  629. //+---------------------------------------------------------------------------
  630. //
  631. // Function: SetupReadFile
  632. //
  633. // Synopsis: Open a file and prepare to read from it.
  634. //
  635. // Arguments: [pszdir] -- Directory name
  636. // [pszfile] -- Filename
  637. // [pszCommentToEOL] -- Comment to EOL string
  638. // [ppf] -- [out] Open file handle
  639. //
  640. // Returns: TRUE if opened successfully
  641. //
  642. // Notes: This function, in order to minimize disk hits, reads the
  643. // entire file into a buffer, which is then used by the ReadLine
  644. // function.
  645. //
  646. //----------------------------------------------------------------------------
  647. BOOL
  648. SetupReadFile(
  649. LPSTR pszdir,
  650. LPSTR pszfile,
  651. LPSTR pszCommentToEOL,
  652. FILE **ppf
  653. )
  654. {
  655. char path[DB_MAX_PATH_LENGTH] = {0};
  656. assert(!Frb.fOpen);
  657. assert(Frb.pf == NULL);
  658. assert(Frb.pszFile == NULL);
  659. Frb.fMakefile = strcmp(pszCommentToEOL, "#") == 0;
  660. Frb.DateTime = 0;
  661. if (strlen(pszdir) > sizeof(path)-1) {
  662. BuildError("Path: %s too long - rebuild build.exe with longer DB_MAX_PATH_LENGTH\n", pszdir);
  663. }
  664. strncpy(path, pszdir, sizeof(path));
  665. if (Frb.pfrbNext != NULL) { // if a nested open
  666. LPSTR p;
  667. if (Frb.fMakefile && !IsFullPath(pszfile)) {
  668. // nmake handles relative includes in makefiles by
  669. // attempting to locate the file relative to each makefile
  670. // in the complete include chain.
  671. FILEREADBUF *pfrb;
  672. for (pfrb = Frb.pfrbNext; pfrb != NULL; pfrb = pfrb->pfrbNext) {
  673. assert(pfrb->pszFile != NULL);
  674. strcpy(path, pfrb->pszFile);
  675. p = strrchr(path, '\\');
  676. if (p != NULL) {
  677. *p = '\0';
  678. }
  679. if (ProbeFile(path, pszfile) != -1) {
  680. break;
  681. }
  682. }
  683. if (pfrb == NULL) {
  684. // Unable to find file anywhere along path.
  685. return FALSE;
  686. }
  687. } else {
  688. p = strrchr(path, '\\');
  689. if (p != NULL) {
  690. *p = '\0';
  691. }
  692. }
  693. }
  694. if (!MyOpenFile(path, pszfile, "rb", ppf, TRUE)) {
  695. *ppf = NULL;
  696. return (FALSE);
  697. }
  698. if (Frb.fMakefile) {
  699. Frb.DateTime = (*pDateTimeFile)(path, pszfile);
  700. }
  701. Frb.cLine = 0;
  702. Frb.cNull = 0;
  703. Frb.cbTotal = 0;
  704. Frb.pf = *ppf;
  705. Frb.fEof = FALSE;
  706. Frb.pszCommentToEOL = pszCommentToEOL;
  707. Frb.cbCommentToEOL = strlen(pszCommentToEOL);
  708. if (fseek(Frb.pf, 0L, SEEK_END) != -1) {
  709. Frb.cbFile = ftell(Frb.pf);
  710. if (fseek(Frb.pf, 0L, SEEK_SET) == -1) {
  711. Frb.cbFile = 0;
  712. }
  713. } else {
  714. Frb.cbFile = 0;
  715. }
  716. Frb.cbBuffer = BigBufSize;
  717. if (Frb.pfrbNext != NULL) {
  718. if (Frb.cbBuffer > Frb.cbFile + 1) {
  719. Frb.cbBuffer = Frb.cbFile + 1;
  720. }
  721. AllocMem(Frb.cbBuffer, &Frb.pbBuffer, MT_IOBUFFER);
  722. } else {
  723. Frb.pbBuffer = BigBuf;
  724. }
  725. if (!ReadBuf(Frb.pf)) {
  726. fclose(Frb.pf);
  727. Frb.pf = *ppf = NULL;
  728. if (Frb.pfrbNext != NULL) {
  729. FreeMem(&Frb.pbBuffer, MT_IOBUFFER);
  730. }
  731. return (FALSE); // zero byte file
  732. }
  733. if (path[0] != '\0') {
  734. strcat(path, "\\");
  735. }
  736. strcat(path, pszfile);
  737. MakeString(&Frb.pszFile, path, TRUE, MT_FRBSTRING);
  738. Frb.fOpen = TRUE;
  739. if (Frb.fMakefile && DEBUG_4) {
  740. BuildError(
  741. "Opening file: cbFile=%Iu cbBuf=%lu\r\n",
  742. Frb.cbTotal,
  743. Frb.cbBuffer);
  744. }
  745. return (TRUE);
  746. }
  747. //+---------------------------------------------------------------------------
  748. //
  749. // Function: CloseReadFile
  750. //
  751. // Synopsis: Close the open file buffer.
  752. //
  753. // Arguments: [pcline] -- [out] Count of lines in file.
  754. //
  755. // Returns: Timestamp of file
  756. //
  757. //----------------------------------------------------------------------------
  758. ULONG
  759. CloseReadFile(
  760. UINT *pcline
  761. )
  762. {
  763. assert(Frb.fOpen);
  764. assert(Frb.pf != NULL);
  765. assert(Frb.pszFile != NULL);
  766. if (Frb.fMakefile && DEBUG_4) {
  767. BuildError("Closing file\r\n");
  768. }
  769. if (Frb.cNull > 1) {
  770. BuildError("%hu null bytes in file\r\n", Frb.cNull);
  771. }
  772. fclose(Frb.pf);
  773. Frb.fOpen = FALSE;
  774. Frb.pf = NULL;
  775. FreeString(&Frb.pszFile, MT_FRBSTRING);
  776. if (Frb.pfrbNext != NULL) {
  777. FILEREADBUF *pfrb;
  778. FreeMem(&Frb.pbBuffer, MT_IOBUFFER);
  779. pfrb = Frb.pfrbNext;
  780. if (pfrb->DateTime < Frb.DateTime) {
  781. pfrb->DateTime = Frb.DateTime; // propagate subordinate timestamp
  782. }
  783. memcpy(&Frb, pfrb, sizeof(*pfrb));
  784. FreeMem(&pfrb, MT_FILEREADBUF);
  785. }
  786. if (pcline != NULL) {
  787. *pcline = Frb.cLine;
  788. }
  789. return (Frb.DateTime);
  790. }
  791. //+---------------------------------------------------------------------------
  792. //
  793. // Function: ProbeFile
  794. //
  795. // Synopsis: Determine if a file exists
  796. //
  797. //----------------------------------------------------------------------------
  798. UINT
  799. ProbeFile(
  800. LPSTR DirName,
  801. LPSTR FileName
  802. )
  803. {
  804. char path[ DB_MAX_PATH_LENGTH ];
  805. if (DirName != NULL) {
  806. sprintf(path, "%s\\%s", DirName, FileName);
  807. FileName = path;
  808. }
  809. return (GetFileAttributes(FileName));
  810. }
  811. //+---------------------------------------------------------------------------
  812. //
  813. // Function: EnsureDirectoriesExist
  814. //
  815. // Synopsis: Ensures the given directory exists. If the path contains
  816. // an asterisk, it will be expanded into all current machine
  817. // target names.
  818. //
  819. // Arguments: [DirName] -- Name of directory to create if necessary
  820. //
  821. // Returns: FALSE if the directory could not be created, TRUE if it
  822. // already exists or it could be created.
  823. //
  824. //----------------------------------------------------------------------------
  825. BOOL
  826. EnsureDirectoriesExist(
  827. LPSTR DirName
  828. )
  829. {
  830. char path[ DB_MAX_PATH_LENGTH ];
  831. char *p;
  832. UINT i;
  833. if (!DirName || DirName[0] == '\0')
  834. return FALSE;
  835. for (i = 0; i < CountTargetMachines; i++) {
  836. // Replace '*' with appropriate name
  837. ExpandObjAsterisk(
  838. path,
  839. DirName,
  840. TargetMachines[i]->ObjectDirectory);
  841. if (ProbeFile(NULL, path) != -1) {
  842. continue;
  843. }
  844. p = path;
  845. while (TRUE) {
  846. p = strchr(p, '\\');
  847. if (p != NULL) {
  848. *p = '\0';
  849. }
  850. if (!CreateBuildDirectory(path)) {
  851. return FALSE;
  852. }
  853. if (p == NULL) {
  854. break;
  855. }
  856. *p++ = '\\';
  857. }
  858. }
  859. return TRUE;
  860. }
  861. //+---------------------------------------------------------------------------
  862. //
  863. // Function: DateTimeFile
  864. //
  865. // Synopsis: Get the timestamp on a file
  866. //
  867. //----------------------------------------------------------------------------
  868. ULONG
  869. DateTimeFile(
  870. LPSTR DirName,
  871. LPSTR FileName
  872. )
  873. {
  874. char path[ DB_MAX_PATH_LENGTH ];
  875. WIN32_FIND_DATA FindFileData;
  876. HDIR FindHandle;
  877. ULONG FileDateTime;
  878. if (DirName == NULL || DirName[0] == '\0') {
  879. FindHandle = FindFirstFile( FileName, &FindFileData );
  880. } else {
  881. _snprintf( path, sizeof(path)-1, "%s\\%s", DirName, FileName );
  882. FindHandle = FindFirstFile( path, &FindFileData );
  883. }
  884. if (FindHandle == (HDIR)INVALID_HANDLE_VALUE) {
  885. return ( 0L );
  886. } else {
  887. FindClose( FindHandle );
  888. FileDateTime = 0L;
  889. FileTimeToDosDateTime( &FindFileData.ftLastWriteTime,
  890. ((LPWORD)&FileDateTime)+1,
  891. (LPWORD)&FileDateTime
  892. );
  893. return ( FileDateTime );
  894. }
  895. }
  896. //+---------------------------------------------------------------------------
  897. //
  898. // Function: DateTimeFile2
  899. //
  900. // Synopsis: Get the timestamp on a file using the new GetFileAttributesExA
  901. //
  902. //----------------------------------------------------------------------------
  903. ULONG
  904. DateTimeFile2(
  905. LPSTR DirName,
  906. LPSTR FileName
  907. )
  908. {
  909. char path[ DB_MAX_PATH_LENGTH ] = {0};
  910. WIN32_FILE_ATTRIBUTE_DATA FileData;
  911. ULONG FileDateTime;
  912. BOOL rc;
  913. if (DirName == NULL || DirName[0] == '\0') {
  914. strncpy( path, FileName, sizeof(path) - 1 );
  915. } else {
  916. _snprintf( path, sizeof(path)-1, "%s\\%s", DirName, FileName );
  917. }
  918. rc = (*pGetFileAttributesExA) (path, GetFileExInfoStandard, (LPVOID)&FileData);
  919. if (!rc) {
  920. return ( 0L );
  921. } else {
  922. FILETIME ftSystemTime;
  923. SYSTEMTIME stSystemTime;
  924. unsigned __int64 ui64Local, ui64File;
  925. GetSystemTime(&stSystemTime);
  926. SystemTimeToFileTime(&stSystemTime, &ftSystemTime);
  927. ui64Local = (((unsigned __int64) ftSystemTime.dwHighDateTime) << 32) +
  928. (unsigned __int64) ftSystemTime.dwLowDateTime;
  929. ui64File = (((unsigned __int64) FileData.ftLastWriteTime.dwHighDateTime) << 32) +
  930. (unsigned __int64) FileData.ftLastWriteTime.dwLowDateTime;
  931. // Take into account that file times may have two second intervals (0x989680 = 1 second)
  932. // for FAT drives.
  933. if (ui64File > (ui64Local + (0x989680*2))) {
  934. BuildError("ERROR - \"%s\" file time is in the future.\r\n", path);
  935. }
  936. FileDateTime = 0L;
  937. FileTimeToDosDateTime( &FileData.ftLastWriteTime,
  938. ((LPWORD)&FileDateTime)+1,
  939. (LPWORD)&FileDateTime
  940. );
  941. return ( FileDateTime );
  942. }
  943. }
  944. //+---------------------------------------------------------------------------
  945. //
  946. // Function: DeleteSingleFile
  947. //
  948. // Synopsis: Delete the given file
  949. //
  950. //----------------------------------------------------------------------------
  951. BOOL
  952. DeleteSingleFile(
  953. LPSTR DirName,
  954. LPSTR FileName,
  955. BOOL QuietFlag
  956. )
  957. {
  958. char path[ DB_MAX_PATH_LENGTH * 2 + 1]; // ensure we have enough space for "DirName" + "\\" + "FileName"
  959. if (DirName) {
  960. sprintf( path, "%s\\%s", DirName, FileName );
  961. } else {
  962. strcpy( path, FileName );
  963. }
  964. if (!QuietFlag && fQuery) {
  965. BuildMsgRaw("'erase %s'\r\n", path);
  966. return ( TRUE );
  967. }
  968. return ( DeleteFile( path ) );
  969. }
  970. //+---------------------------------------------------------------------------
  971. //
  972. // Function: DeleteMultipleFiles
  973. //
  974. // Synopsis: Delete one or more files matching a pattern.
  975. //
  976. //----------------------------------------------------------------------------
  977. BOOL
  978. DeleteMultipleFiles(
  979. LPSTR DirName,
  980. LPSTR FilePattern
  981. )
  982. {
  983. char path[ DB_MAX_PATH_LENGTH ];
  984. WIN32_FIND_DATA FindFileData;
  985. HDIR FindHandle;
  986. sprintf( path, "%s\\%s", DirName, FilePattern );
  987. if (fQuery) {
  988. BuildMsgRaw("'erase %s'\r\n", path);
  989. return ( TRUE );
  990. }
  991. FindHandle = FindFirstFile( path, &FindFileData );
  992. if (FindHandle == (HDIR)INVALID_HANDLE_VALUE) {
  993. return ( FALSE );
  994. }
  995. do {
  996. if (!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  997. DeleteSingleFile( DirName, FindFileData.cFileName, TRUE );
  998. }
  999. }
  1000. while (FindNextFile( FindHandle, &FindFileData ));
  1001. FindClose( FindHandle );
  1002. return ( TRUE );
  1003. }
  1004. //+---------------------------------------------------------------------------
  1005. //
  1006. // Function: CloseOrDeleteFile
  1007. //
  1008. //----------------------------------------------------------------------------
  1009. BOOL
  1010. CloseOrDeleteFile(
  1011. FILE **ppf,
  1012. LPSTR DirName,
  1013. LPSTR FileName,
  1014. ULONG SizeThreshold
  1015. )
  1016. {
  1017. ULONG Temp;
  1018. if (*ppf == NULL) {
  1019. return TRUE;
  1020. }
  1021. Temp = ftell( *ppf );
  1022. fclose( *ppf );
  1023. *ppf = NULL;
  1024. if (Temp <= SizeThreshold) {
  1025. return ( DeleteSingleFile( DirName, FileName, TRUE ) );
  1026. } else {
  1027. CreatedBuildFile(DirName, FileName);
  1028. return ( TRUE );
  1029. }
  1030. }
  1031. //+---------------------------------------------------------------------------
  1032. //
  1033. // Function: PushCurrentDirectory
  1034. //
  1035. //----------------------------------------------------------------------------
  1036. LPSTR
  1037. PushCurrentDirectory(
  1038. LPSTR NewCurrentDirectory
  1039. )
  1040. {
  1041. LPSTR OldCurrentDirectory;
  1042. char path[DB_MAX_PATH_LENGTH];
  1043. GetCurrentDirectory(sizeof(path), path);
  1044. AllocMem(strlen(path) + 1, &OldCurrentDirectory, MT_DIRPATH);
  1045. strcpy(OldCurrentDirectory, path);
  1046. SetCurrentDirectory(NewCurrentDirectory);
  1047. return (OldCurrentDirectory);
  1048. }
  1049. //+---------------------------------------------------------------------------
  1050. //
  1051. // Function: PopCurrentDirectory
  1052. //
  1053. //----------------------------------------------------------------------------
  1054. VOID
  1055. PopCurrentDirectory(
  1056. LPSTR OldCurrentDirectory
  1057. )
  1058. {
  1059. if (OldCurrentDirectory) {
  1060. SetCurrentDirectory(OldCurrentDirectory);
  1061. FreeMem(&OldCurrentDirectory, MT_DIRPATH);
  1062. }
  1063. }
  1064. //+---------------------------------------------------------------------------
  1065. //
  1066. // Function: CanonicalizePathName
  1067. //
  1068. // Synopsis: Take the given relative pathname and the current directory
  1069. // and obtain the full absolute path of the file.
  1070. //
  1071. // Arguments: [SourcePath] -- Relative path
  1072. // [Action] -- Canonicalizing flags
  1073. // [FullPath] -- [out] Full path of file or directory
  1074. //
  1075. // Returns: TRUE if canonicalization succeeded.
  1076. //
  1077. // Notes: [Action] indicates whether the function will fail if the
  1078. // resulting path is not of the correct type. CANONICALIZE_ONLY
  1079. // never fails, and CANON..._FILE or CANON..._DIR will fail if
  1080. // the resulting path is not of the specified type.
  1081. //
  1082. //----------------------------------------------------------------------------
  1083. BOOL
  1084. CanonicalizePathName(
  1085. LPSTR SourcePath,
  1086. UINT Action,
  1087. LPSTR FullPath
  1088. )
  1089. {
  1090. char PathBuffer[DB_MAX_PATH_LENGTH] = {0},
  1091. *FilePart;
  1092. char *psz;
  1093. DWORD attr;
  1094. if (!GetFullPathName(
  1095. SourcePath,
  1096. sizeof(PathBuffer),
  1097. PathBuffer,
  1098. &FilePart)) {
  1099. BuildError(
  1100. "CanonicalizePathName: GetFullPathName(%s) failed - rc = %d.\r\n",
  1101. SourcePath,
  1102. GetLastError());
  1103. return ( FALSE );
  1104. }
  1105. CopyString(FullPath, PathBuffer, TRUE);
  1106. if (Action == CANONICALIZE_ONLY) {
  1107. return ( TRUE );
  1108. }
  1109. if ((attr = GetFileAttributes( PathBuffer )) == -1) {
  1110. UINT rc = GetLastError();
  1111. if (DEBUG_1 ||
  1112. (rc != ERROR_FILE_NOT_FOUND && rc != ERROR_PATH_NOT_FOUND)) {
  1113. BuildError(
  1114. "CanonicalizePathName: GetFileAttributes(%s --> %s) failed - rc = %d.\r\n",
  1115. SourcePath,
  1116. PathBuffer,
  1117. rc);
  1118. }
  1119. return ( FALSE );
  1120. }
  1121. if (Action == CANONICALIZE_DIR) {
  1122. if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
  1123. return (TRUE);
  1124. }
  1125. psz = "directory";
  1126. } else {
  1127. if ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
  1128. return (TRUE);
  1129. }
  1130. psz = "file";
  1131. }
  1132. BuildError(
  1133. "CanonicalizePathName: %s --> %s is not a %s\r\n",
  1134. SourcePath,
  1135. PathBuffer,
  1136. psz);
  1137. return (FALSE);
  1138. }
  1139. static char FormatPathBuffer[ DB_MAX_PATH_LENGTH ];
  1140. //+---------------------------------------------------------------------------
  1141. //
  1142. // Function: FormatPathName
  1143. //
  1144. // Synopsis: Take a directory name and relative pathname and merges the
  1145. // two into a correctly formatted path. If the resulting path
  1146. // has the current directory as a component, the current
  1147. // directory part is removed.
  1148. //
  1149. // Arguments: [DirName] -- Directory
  1150. // [FileName] -- Pathname relative to [DirName]
  1151. //
  1152. // Returns: Resulting string (should not be freed).
  1153. //
  1154. // Notes: Example: DirName="f:\nt\private\foo\subdir1\subdir2"
  1155. // FileName="..\..\bar.c"
  1156. // CurrentDirectory="f:\nt\private"
  1157. // Result="foo\bar.c"
  1158. //
  1159. //----------------------------------------------------------------------------
  1160. LPSTR
  1161. FormatPathName(
  1162. LPSTR DirName,
  1163. LPSTR FileName
  1164. )
  1165. {
  1166. UINT cb;
  1167. LPSTR p;
  1168. CopyString(FormatPathBuffer, CurrentDirectory, TRUE);
  1169. if (DirName && *DirName) {
  1170. if (DirName[1] == ':') {
  1171. p = FormatPathBuffer;
  1172. } else
  1173. if (DirName[0] == '\\') {
  1174. p = FormatPathBuffer + 2;
  1175. } else {
  1176. p = FormatPathBuffer + strlen(FormatPathBuffer);
  1177. *p++ = '\\';
  1178. }
  1179. CopyString(p, DirName, TRUE);
  1180. }
  1181. p = FormatPathBuffer + strlen(FormatPathBuffer);
  1182. if (p[-1] != '\\') {
  1183. *p++ = '\\';
  1184. *p = '\0';
  1185. }
  1186. if (FileName[1] == ':') {
  1187. p = FormatPathBuffer;
  1188. } else
  1189. if (FileName[0] == '\\') {
  1190. p = FormatPathBuffer + 2;
  1191. } else
  1192. if (!strncmp(FileName, ".\\", 2)) {
  1193. FileName += 2;
  1194. } else
  1195. if (!strncmp(FileName, "..\\", 3)) {
  1196. do {
  1197. p--;
  1198. while (*--p != '\\') {
  1199. if (p <= FormatPathBuffer) {
  1200. p = FormatPathBuffer;
  1201. break;
  1202. }
  1203. }
  1204. p++;
  1205. FileName += 3;
  1206. }
  1207. while (!strncmp(FileName, "..\\", 3) && (p != FormatPathBuffer));
  1208. }
  1209. CopyString(p, FileName, TRUE);
  1210. cb = strlen(CurrentDirectory);
  1211. p = FormatPathBuffer + cb;
  1212. if (!fAlwaysPrintFullPath) {
  1213. if (!_strnicmp(CurrentDirectory, FormatPathBuffer, cb) && *p == '\\') {
  1214. return (p + 1);
  1215. }
  1216. }
  1217. return (FormatPathBuffer);
  1218. }
  1219. //+---------------------------------------------------------------------------
  1220. //
  1221. // Function: AppendString
  1222. //
  1223. //----------------------------------------------------------------------------
  1224. LPSTR
  1225. AppendString(
  1226. LPSTR Destination,
  1227. LPSTR Source,
  1228. BOOL PrefixWithSpace
  1229. )
  1230. {
  1231. if (Source != NULL) {
  1232. while (*Destination) {
  1233. Destination++;
  1234. }
  1235. if (PrefixWithSpace) {
  1236. *Destination++ = ' ';
  1237. }
  1238. while (*Destination = *Source++) {
  1239. Destination++;
  1240. }
  1241. }
  1242. return (Destination);
  1243. }
  1244. #if DBG
  1245. //+---------------------------------------------------------------------------
  1246. //
  1247. // Function: AssertPathString
  1248. //
  1249. //----------------------------------------------------------------------------
  1250. VOID
  1251. AssertPathString(LPSTR pszPath)
  1252. {
  1253. LPSTR p = pszPath;
  1254. while (*p != '\0') {
  1255. if ((*p >= 'A' && *p <= 'Z') || *p == '/') {
  1256. BuildError("Bad Path string: '%s'\r\n", pszPath);
  1257. assert(FALSE);
  1258. }
  1259. p++;
  1260. }
  1261. }
  1262. #endif
  1263. //+---------------------------------------------------------------------------
  1264. //
  1265. // Function: CopyString
  1266. //
  1267. //----------------------------------------------------------------------------
  1268. LPSTR
  1269. CopyString(
  1270. LPSTR Destination,
  1271. LPSTR Source,
  1272. BOOL fPath)
  1273. {
  1274. UCHAR ch;
  1275. LPSTR Result;
  1276. Result = Destination;
  1277. while ((ch = *Source++) != '\0') {
  1278. if (fPath) {
  1279. if (ch >= 'A' && ch <= 'Z') {
  1280. ch -= (UCHAR) ('A' - 'a');
  1281. } else if (ch == '/') {
  1282. ch = '\\';
  1283. }
  1284. }
  1285. *Destination++ = ch;
  1286. }
  1287. *Destination = ch;
  1288. return (Result);
  1289. }
  1290. //+---------------------------------------------------------------------------
  1291. //
  1292. // Function: MakeString
  1293. //
  1294. //----------------------------------------------------------------------------
  1295. VOID
  1296. MakeString(
  1297. LPSTR *Destination,
  1298. LPSTR Source,
  1299. BOOL fPath,
  1300. MemType mt
  1301. )
  1302. {
  1303. if (Source == NULL) {
  1304. Source = "";
  1305. }
  1306. AllocMem(strlen(Source) + 1, Destination, mt);
  1307. *Destination = CopyString(*Destination, Source, fPath);
  1308. }
  1309. //+---------------------------------------------------------------------------
  1310. //
  1311. // Function: MakeExpandedString
  1312. //
  1313. //----------------------------------------------------------------------------
  1314. VOID
  1315. MakeExpandedString(
  1316. LPSTR *Destination,
  1317. LPSTR Source
  1318. )
  1319. {
  1320. AllocMem(strlen(Source) + strlen(NtRoot) + 1, Destination, MT_DIRSTRING);
  1321. sprintf(*Destination, "%s%s", NtRoot, Source);
  1322. }
  1323. //+---------------------------------------------------------------------------
  1324. //
  1325. // Function: FreeString
  1326. //
  1327. //----------------------------------------------------------------------------
  1328. VOID
  1329. FreeString(LPSTR *ppsz, MemType mt)
  1330. {
  1331. if (*ppsz != NULL) {
  1332. FreeMem(ppsz, mt);
  1333. }
  1334. }
  1335. //+---------------------------------------------------------------------------
  1336. //
  1337. // Function: FormatNumber
  1338. //
  1339. //----------------------------------------------------------------------------
  1340. LPSTR
  1341. FormatNumber(
  1342. ULONG Number
  1343. )
  1344. {
  1345. USHORT i;
  1346. LPSTR p;
  1347. static char FormatNumberBuffer[16];
  1348. p = FormatNumberBuffer + sizeof( FormatNumberBuffer ) - 1;
  1349. *p = '\0';
  1350. i = 0;
  1351. do {
  1352. if (i != 0 && (i % 3) == 0) {
  1353. *--p = ',';
  1354. }
  1355. i++;
  1356. *--p = (UCHAR) ((Number % 10) + '0');
  1357. Number /= 10;
  1358. } while (Number != 0);
  1359. return ( p );
  1360. }
  1361. //+---------------------------------------------------------------------------
  1362. //
  1363. // Function: FormatTime
  1364. //
  1365. //----------------------------------------------------------------------------
  1366. LPSTR
  1367. FormatTime(
  1368. ULONG Seconds
  1369. )
  1370. {
  1371. ULONG Hours, Minutes;
  1372. static char FormatTimeBuffer[16];
  1373. Hours = Seconds / 3600;
  1374. Seconds = Seconds % 3600;
  1375. Minutes = Seconds / 60;
  1376. Seconds = Seconds % 60;
  1377. sprintf( FormatTimeBuffer,
  1378. "%2ld:%02ld:%02ld",
  1379. Hours,
  1380. Minutes,
  1381. Seconds
  1382. );
  1383. return ( FormatTimeBuffer );
  1384. }
  1385. //+---------------------------------------------------------------------------
  1386. //
  1387. // Function: AToX
  1388. //
  1389. // Synopsis: Hex atoi with pointer bumping and success flag
  1390. //
  1391. // Arguments: [pp] -- String to convert
  1392. // [pul] -- [out] Result
  1393. //
  1394. // Returns: TRUE if success
  1395. //
  1396. //----------------------------------------------------------------------------
  1397. BOOL
  1398. AToX(LPSTR *pp, ULONG *pul)
  1399. {
  1400. LPSTR p = *pp;
  1401. int digit;
  1402. ULONG r;
  1403. BOOL fRet = FALSE;
  1404. while (*p == ' ') {
  1405. p++;
  1406. }
  1407. for (r = 0; isxdigit(digit = *p); p++) {
  1408. fRet = TRUE;
  1409. if (isdigit(digit)) {
  1410. digit -= '0';
  1411. } else if (isupper(digit)) {
  1412. digit -= 'A' - 10;
  1413. } else {
  1414. digit -= 'a' - 10;
  1415. }
  1416. r = (r << 4) + digit;
  1417. }
  1418. *pp = p;
  1419. *pul = r;
  1420. return (fRet);
  1421. }
  1422. //+---------------------------------------------------------------------------
  1423. //
  1424. // Function: AToD
  1425. //
  1426. // Synopsis: Decimal atoi with pointer bumping and success flag
  1427. //
  1428. // Arguments: [pp] -- String to convert
  1429. // [pul] -- [out] Result
  1430. //
  1431. // Returns: TRUE if success
  1432. //
  1433. //----------------------------------------------------------------------------
  1434. BOOL
  1435. AToD(LPSTR *pp, ULONG *pul)
  1436. {
  1437. LPSTR p = *pp;
  1438. int digit;
  1439. ULONG r;
  1440. BOOL fRet = FALSE;
  1441. while (*p == ' ') {
  1442. p++;
  1443. }
  1444. for (r = 0; isdigit(digit = *p); p++) {
  1445. fRet = TRUE;
  1446. r = (r * 10) + digit - '0';
  1447. }
  1448. *pp = p;
  1449. *pul = r;
  1450. return (fRet);
  1451. }
  1452. //+---------------------------------------------------------------------------
  1453. //
  1454. // Logging and Display Functions
  1455. //
  1456. //----------------------------------------------------------------------------
  1457. VOID
  1458. __cdecl
  1459. LogMsg(const char *pszfmt, ...)
  1460. {
  1461. va_list va;
  1462. if (LogFile != NULL) {
  1463. va_start(va, pszfmt);
  1464. vfprintf(LogFile, pszfmt, va);
  1465. va_end(va);
  1466. }
  1467. }
  1468. VOID
  1469. EnterMessageMode(VOID)
  1470. {
  1471. EnterCriticalSection(&TTYCriticalSection);
  1472. if (fConsoleInitialized &&
  1473. (NewConsoleMode & ENABLE_WRAP_AT_EOL_OUTPUT) == 0) {
  1474. SetConsoleMode(
  1475. GetStdHandle(STD_ERROR_HANDLE),
  1476. NewConsoleMode | ENABLE_WRAP_AT_EOL_OUTPUT);
  1477. }
  1478. }
  1479. VOID
  1480. LeaveMessageMode(VOID)
  1481. {
  1482. if (fConsoleInitialized &&
  1483. (NewConsoleMode & ENABLE_WRAP_AT_EOL_OUTPUT) == 0) {
  1484. SetConsoleMode(GetStdHandle(STD_ERROR_HANDLE), NewConsoleMode);
  1485. }
  1486. LeaveCriticalSection(&TTYCriticalSection);
  1487. }
  1488. void
  1489. __stdcall
  1490. WriteMsgStdErr(
  1491. WORD wAttributes,
  1492. BOOL fBuildPrefix,
  1493. BOOL fPrintFrbInfo,
  1494. const char *pszFormat,
  1495. va_list *vaArgs)
  1496. {
  1497. EnterMessageMode();
  1498. if (fBuildPrefix)
  1499. ClearLine();
  1500. if (fColorConsole && wAttributes)
  1501. SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), wAttributes);
  1502. if (fBuildPrefix)
  1503. fprintf(stderr, "BUILD: ");
  1504. if (fPrintFrbInfo && Frb.fOpen) {
  1505. fprintf (stderr, "%s(%hu): ", Frb.pszFile, Frb.cLine);
  1506. }
  1507. vfprintf(stderr, pszFormat, *vaArgs);
  1508. fflush(stderr);
  1509. if (fColorConsole && wAttributes)
  1510. SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), DefaultConsoleAttributes);
  1511. LeaveMessageMode();
  1512. }
  1513. VOID
  1514. __cdecl
  1515. BuildMsg(const char *pszfmt, ...)
  1516. {
  1517. va_list va;
  1518. va_start(va, pszfmt);
  1519. WriteMsgStdErr(0, TRUE, FALSE, pszfmt, &va);
  1520. }
  1521. void
  1522. __cdecl
  1523. BuildColorMsg(WORD wAttributes, const char *pszfmt, ...)
  1524. {
  1525. va_list va;
  1526. va_start(va, pszfmt);
  1527. WriteMsgStdErr(wAttributes, TRUE, FALSE, pszfmt, &va);
  1528. }
  1529. VOID
  1530. __cdecl
  1531. BuildMsgRaw(const char *pszfmt, ...)
  1532. {
  1533. va_list va;
  1534. va_start(va, pszfmt);
  1535. WriteMsgStdErr(0, FALSE, FALSE, pszfmt, &va);
  1536. }
  1537. VOID
  1538. __cdecl
  1539. BuildColorMsgRaw(WORD wAttributes, const char *pszfmt, ...)
  1540. {
  1541. va_list va;
  1542. va_start(va, pszfmt);
  1543. WriteMsgStdErr(wAttributes, FALSE, FALSE, pszfmt, &va);
  1544. }
  1545. VOID
  1546. __cdecl
  1547. BuildError(const char *pszfmt, ...)
  1548. {
  1549. va_list va;
  1550. va_start(va, pszfmt);
  1551. WriteMsgStdErr(0, TRUE, TRUE, pszfmt, &va);
  1552. if (LogFile != NULL) {
  1553. va_start(va, pszfmt);
  1554. fprintf(LogFile, "BUILD: ");
  1555. if (Frb.fOpen) {
  1556. fprintf (LogFile, "%s(%hu): ", Frb.pszFile, Frb.cLine);
  1557. }
  1558. vfprintf(LogFile, pszfmt, va);
  1559. va_end(va);
  1560. fflush(LogFile);
  1561. }
  1562. }
  1563. VOID
  1564. __cdecl
  1565. BuildColorError(WORD wAttributes, const char *pszfmt, ...)
  1566. {
  1567. va_list va;
  1568. va_start(va, pszfmt);
  1569. WriteMsgStdErr(wAttributes, TRUE, TRUE, pszfmt, &va);
  1570. if (LogFile != NULL) {
  1571. va_start(va, pszfmt);
  1572. fprintf(LogFile, "BUILD: ");
  1573. if (Frb.fOpen) {
  1574. fprintf (LogFile, "%s(%hu): ", Frb.pszFile, Frb.cLine);
  1575. }
  1576. vfprintf(LogFile, pszfmt, va);
  1577. va_end(va);
  1578. fflush(LogFile);
  1579. }
  1580. }
  1581. VOID
  1582. __cdecl
  1583. BuildErrorRaw(const char *pszfmt, ...)
  1584. {
  1585. va_list va;
  1586. va_start(va, pszfmt);
  1587. WriteMsgStdErr(0, FALSE, FALSE, pszfmt, &va);
  1588. if (LogFile != NULL) {
  1589. va_start(va, pszfmt);
  1590. vfprintf(LogFile, pszfmt, va);
  1591. va_end(va);
  1592. fflush(LogFile);
  1593. }
  1594. }
  1595. VOID
  1596. __cdecl
  1597. BuildColorErrorRaw(WORD wAttributes, const char *pszfmt, ...)
  1598. {
  1599. va_list va;
  1600. va_start(va, pszfmt);
  1601. WriteMsgStdErr(wAttributes, FALSE, FALSE, pszfmt, &va);
  1602. if (LogFile != NULL) {
  1603. va_start(va, pszfmt);
  1604. vfprintf(LogFile, pszfmt, va);
  1605. va_end(va);
  1606. fflush(LogFile);
  1607. }
  1608. }
  1609. //+---------------------------------------------------------------------------
  1610. //
  1611. // Function: memfind
  1612. //
  1613. // Synopsis: Finds a sub-string by length (can contain nulls)
  1614. //
  1615. // Arguments: [pvWhere] -- String to search (can contain nulls)
  1616. // [cbWhere] -- Length in bytes of the string to search
  1617. // [pvWhat] -- String to search for (can contain nulls)
  1618. // [cbWhat] -- Length in bytes of the string to search for
  1619. //
  1620. // Returns: Pointer to the first occurence of pvWhat in pvWhere
  1621. // NULL, if not found or if the input parameters are not valid
  1622. //
  1623. //----------------------------------------------------------------------------
  1624. VOID*
  1625. memfind(VOID* pvWhere, DWORD cbWhere, VOID* pvWhat, DWORD cbWhat)
  1626. {
  1627. DWORD dwWhat = 0;
  1628. DWORD dwWhere = 0;
  1629. DWORD dwFoundStart = 0;
  1630. // input validation
  1631. if (cbWhere < cbWhat || pvWhere == NULL || pvWhat == NULL)
  1632. return NULL;
  1633. while (dwFoundStart <= cbWhere - cbWhat && dwWhat < cbWhat) {
  1634. if ( ((BYTE*)pvWhat)[dwWhat] != ((BYTE*)pvWhere)[dwWhere]) {
  1635. dwWhat = 0;
  1636. dwFoundStart++;
  1637. dwWhere = dwFoundStart;
  1638. } else {
  1639. dwWhat++;
  1640. dwWhere++;
  1641. }
  1642. }
  1643. if (dwWhat == cbWhat)
  1644. return (BYTE*)pvWhere + dwFoundStart;
  1645. return NULL;
  1646. }
  1647. //
  1648. // XML Logging
  1649. //
  1650. //#define MAX_XML_BUFFER_SIZE 2048
  1651. char szXMLPrivateBuffer[2048];//MAX_XML_BUFFER_SIZE];
  1652. BOOL
  1653. XMLInit(VOID)
  1654. {
  1655. UINT i;
  1656. if (fXMLOutput) {
  1657. // copy the XML schema to the log directory
  1658. char buffer[MAX_PATH];
  1659. char* psz = buffer + GetModuleFileName(NULL, buffer, sizeof(buffer));
  1660. while (psz > buffer && *psz != '\\') {
  1661. --psz;
  1662. }
  1663. ++psz;
  1664. strcpy(psz, XML_SCHEMA);
  1665. // check if there is a schema file in the current directory
  1666. if (GetFileAttributes(XML_SCHEMA) == 0xFFFFFFFF) {
  1667. // copy the schema to the current directory
  1668. if (!CopyFile(buffer, XML_SCHEMA, FALSE)) {
  1669. BuildError("(Fatal Error) Unable to copy the XML schema file\n");
  1670. return FALSE;
  1671. }
  1672. }
  1673. }
  1674. if (fXMLOutput || fXMLFragment) {
  1675. // initialize the memory structures
  1676. AllocMem(sizeof(PXMLTHREADSTATE)*(NumberProcesses+1), (VOID**)&PXMLThreadStates, MT_PXMLTHREADSTATE);
  1677. for (i = 0; i < NumberProcesses+1; i++) {
  1678. AllocMem(sizeof(XMLTHREADSTATE), (VOID**)&(PXMLThreadStates[i]), MT_XMLTHREADSTATE);
  1679. memset(PXMLThreadStates[i], 0, sizeof(XMLTHREADSTATE));
  1680. PXMLThreadStates[i]->iXMLFileStart = -1;
  1681. }
  1682. AllocMem(sizeof(XMLTHREADSTATE), (VOID**)&(PXMLGlobalState), MT_XMLTHREADSTATE);
  1683. memset(PXMLGlobalState, 0, sizeof(XMLTHREADSTATE));
  1684. PXMLGlobalState->iXMLFileStart = 0;
  1685. InitializeCriticalSection(&XMLCriticalSection);
  1686. fXMLInitialized = TRUE;
  1687. }
  1688. return TRUE;
  1689. }
  1690. VOID
  1691. XMLUnInit(VOID)
  1692. {
  1693. if (fXMLInitialized) {
  1694. UINT i;
  1695. for (i = 0; i < NumberProcesses+1; i++) {
  1696. FreeMem((VOID**)&(PXMLThreadStates[i]), MT_XMLTHREADSTATE);
  1697. }
  1698. FreeMem((VOID**)&PXMLGlobalState, MT_XMLTHREADSTATE);
  1699. FreeMem((VOID**)&PXMLThreadStates, MT_PXMLTHREADSTATE);
  1700. DeleteCriticalSection(&XMLCriticalSection);
  1701. fXMLInitialized = FALSE;
  1702. }
  1703. }
  1704. VOID _cdecl
  1705. XMLThreadWrite(PTHREADSTATE ThreadState, LPCSTR pszFmt, ...)
  1706. {
  1707. va_list va;
  1708. DWORD dwBufferLen;
  1709. SIZE_T dwCurrentFilePos;
  1710. PXMLTHREADSTATE OtherXMLState;
  1711. PXMLTHREADSTATE XMLState;
  1712. UINT i;
  1713. if (!fXMLInitialized)
  1714. return;
  1715. XMLEnterCriticalSection();
  1716. XMLState = PXMLThreadStates[ThreadState->XMLThreadIndex];
  1717. XMLThreadInitBuffer(ThreadState);
  1718. ZeroMemory(szXMLPrivateBuffer, sizeof(szXMLPrivateBuffer));
  1719. // build the string to write out
  1720. va_start(va, pszFmt);
  1721. _vsnprintf(szXMLPrivateBuffer, sizeof(szXMLPrivateBuffer)-1, pszFmt, va);
  1722. va_end(va);
  1723. dwBufferLen = strlen(szXMLPrivateBuffer);
  1724. dwCurrentFilePos = XMLState->iXMLFileStart + XMLState->iXMLBufferPos;
  1725. if (fXMLOutput) {
  1726. // write it into the file
  1727. if (fseek(XMLFile, (long)dwCurrentFilePos, SEEK_SET) != -1) {
  1728. fwrite(szXMLPrivateBuffer, 1, dwBufferLen, XMLFile);
  1729. // put back the thread tail
  1730. fwrite(XMLState->XMLBuffer + XMLState->iXMLBufferPos, 1, XMLState->iXMLBufferLen - XMLState->iXMLBufferPos, XMLFile);
  1731. }
  1732. }
  1733. dwCurrentFilePos += dwBufferLen + XMLState->iXMLBufferLen - XMLState->iXMLBufferPos;
  1734. // insert the string into the thread buffer
  1735. memmove(XMLState->XMLBuffer + XMLState->iXMLBufferPos + dwBufferLen, XMLState->XMLBuffer + XMLState->iXMLBufferPos, XMLState->iXMLBufferLen - XMLState->iXMLBufferPos + 1); // include the null terminator
  1736. memmove(XMLState->XMLBuffer + XMLState->iXMLBufferPos, szXMLPrivateBuffer, dwBufferLen);
  1737. XMLState->iXMLBufferPos += dwBufferLen;
  1738. XMLState->iXMLBufferLen += dwBufferLen;
  1739. // write back the threads that got overwritten
  1740. // will reorder them but it doesn't really matter since the final order is
  1741. // the one in they finish
  1742. for (i = 0; i < NumberProcesses+1; i++) {
  1743. if (i != ThreadState->XMLThreadIndex) {
  1744. OtherXMLState = PXMLThreadStates[i];
  1745. if (OtherXMLState->iXMLFileStart < XMLState->iXMLFileStart) {
  1746. continue;
  1747. }
  1748. OtherXMLState->iXMLFileStart = dwCurrentFilePos;
  1749. if (fXMLOutput) {
  1750. fwrite(OtherXMLState->XMLBuffer, 1, OtherXMLState->iXMLBufferLen, XMLFile);
  1751. }
  1752. dwCurrentFilePos += OtherXMLState->iXMLBufferLen;
  1753. }
  1754. }
  1755. // update the global tail position
  1756. PXMLGlobalState->iXMLFileStart = dwCurrentFilePos;
  1757. if (fXMLOutput) {
  1758. // write back the global tail
  1759. fwrite(PXMLGlobalState->XMLBuffer, 1, PXMLGlobalState->iXMLBufferLen, XMLFile);
  1760. fflush(XMLFile);
  1761. }
  1762. XMLLeaveCriticalSection();
  1763. }
  1764. VOID _cdecl
  1765. XMLThreadOpenTag(PTHREADSTATE ThreadState, LPCSTR pszTag, LPCSTR pszFmt, ...)
  1766. {
  1767. va_list va;
  1768. DWORD dwMidBufferLen;
  1769. DWORD dwBufferLen;
  1770. SIZE_T dwCurrentFilePos;
  1771. DWORD dwTagLen = strlen(pszTag);
  1772. PXMLTHREADSTATE OtherXMLState;
  1773. PXMLTHREADSTATE XMLState;
  1774. UINT i;
  1775. if (!fXMLInitialized)
  1776. return;
  1777. XMLEnterCriticalSection();
  1778. XMLState = PXMLThreadStates[ThreadState->XMLThreadIndex];
  1779. XMLThreadInitBuffer(ThreadState);
  1780. // build the string to write out
  1781. szXMLPrivateBuffer[0] = '<';
  1782. strcpy(szXMLPrivateBuffer + 1, pszTag);
  1783. if (pszFmt != NULL) {
  1784. va_start(va, pszFmt);
  1785. strcat(szXMLPrivateBuffer, " ");
  1786. vsprintf(szXMLPrivateBuffer + strlen(szXMLPrivateBuffer), pszFmt, va);
  1787. va_end(va);
  1788. }
  1789. strcat(szXMLPrivateBuffer, ">");
  1790. dwMidBufferLen = strlen(szXMLPrivateBuffer);
  1791. szXMLPrivateBuffer[dwMidBufferLen] = '<';
  1792. szXMLPrivateBuffer[dwMidBufferLen + 1] = '/';
  1793. memcpy(szXMLPrivateBuffer + dwMidBufferLen + 2, pszTag, dwTagLen);
  1794. szXMLPrivateBuffer[dwMidBufferLen + dwTagLen + 2] = '>';
  1795. dwBufferLen = dwMidBufferLen + dwTagLen + 3;
  1796. // write it into the file
  1797. dwCurrentFilePos = XMLState->iXMLFileStart + XMLState->iXMLBufferPos;
  1798. if (fXMLOutput) {
  1799. if (fseek(XMLFile, (long)dwCurrentFilePos, SEEK_SET) != -1) {
  1800. fwrite(szXMLPrivateBuffer, 1, dwBufferLen, XMLFile);
  1801. // put back the thread tail
  1802. fwrite(XMLState->XMLBuffer + XMLState->iXMLBufferPos, 1, XMLState->iXMLBufferLen - XMLState->iXMLBufferPos, XMLFile);
  1803. }
  1804. }
  1805. dwCurrentFilePos += dwBufferLen + XMLState->iXMLBufferLen - XMLState->iXMLBufferPos;
  1806. // insert the string into the thread buffer
  1807. memmove(XMLState->XMLBuffer + XMLState->iXMLBufferPos + dwBufferLen, XMLState->XMLBuffer + XMLState->iXMLBufferPos, XMLState->iXMLBufferLen - XMLState->iXMLBufferPos + 1); // include the null terminator
  1808. memmove(XMLState->XMLBuffer + XMLState->iXMLBufferPos, szXMLPrivateBuffer, dwBufferLen);
  1809. // don't increase the buffer pos with the full string length but until the end of the open tag only
  1810. XMLState->iXMLBufferPos += dwMidBufferLen;
  1811. XMLState->iXMLBufferLen += dwBufferLen;
  1812. // write back the threads that got overwritten
  1813. // will reorder them but it doesn't really matter since the final order is
  1814. // the one in they finish
  1815. for (i = 0; i < NumberProcesses+1; i++) {
  1816. if (i != ThreadState->XMLThreadIndex) {
  1817. OtherXMLState = PXMLThreadStates[i];
  1818. if (OtherXMLState->iXMLFileStart < XMLState->iXMLFileStart) {
  1819. continue;
  1820. }
  1821. OtherXMLState->iXMLFileStart = dwCurrentFilePos;
  1822. if (fXMLOutput) {
  1823. fwrite(OtherXMLState->XMLBuffer, 1, OtherXMLState->iXMLBufferLen, XMLFile);
  1824. }
  1825. dwCurrentFilePos += OtherXMLState->iXMLBufferLen;
  1826. }
  1827. }
  1828. // update the global tail position
  1829. PXMLGlobalState->iXMLFileStart = dwCurrentFilePos;
  1830. if (fXMLOutput) {
  1831. // write back the global tail
  1832. fwrite(PXMLGlobalState->XMLBuffer, 1, PXMLGlobalState->iXMLBufferLen, XMLFile);
  1833. fflush(XMLFile);
  1834. }
  1835. XMLLeaveCriticalSection();
  1836. }
  1837. VOID
  1838. XMLThreadCloseTag(PTHREADSTATE ThreadState, LPCSTR pszTag)
  1839. {
  1840. PXMLTHREADSTATE XMLState;
  1841. char* psz;
  1842. if (!fXMLInitialized)
  1843. return;
  1844. XMLEnterCriticalSection();
  1845. XMLState = PXMLThreadStates[ThreadState->XMLThreadIndex];
  1846. psz = XMLState->XMLBuffer + XMLState->iXMLBufferPos;
  1847. if (XMLState->iXMLFileStart == -1) {
  1848. XMLLeaveCriticalSection();
  1849. return;
  1850. }
  1851. assert(*psz == '<');
  1852. assert(strncmp(psz+2, pszTag, strlen(pszTag))==0);
  1853. while (*psz != '>')
  1854. psz++;
  1855. psz++;
  1856. XMLState->iXMLBufferPos += psz - (XMLState->XMLBuffer + XMLState->iXMLBufferPos);
  1857. XMLLeaveCriticalSection();
  1858. }
  1859. VOID
  1860. XMLThreadReleaseBuffer(PTHREADSTATE ThreadState)
  1861. {
  1862. // this op may cause the other thread blocks to move towards the end of the file
  1863. // but we can't keep more than one block per thread so we have to live with it
  1864. UINT i;
  1865. SIZE_T iMinFileStart = LONG_MAX;
  1866. int iMinThreadIndex = -1;
  1867. PXMLTHREADSTATE OtherXMLState;
  1868. PXMLTHREADSTATE XMLState;
  1869. SIZE_T dwCurrentFilePos;
  1870. if (!fXMLInitialized)
  1871. return;
  1872. XMLEnterCriticalSection();
  1873. XMLState = PXMLThreadStates[ThreadState->XMLThreadIndex];
  1874. if (XMLState->iXMLFileStart == -1) {
  1875. XMLLeaveCriticalSection();
  1876. return;
  1877. }
  1878. assert(XMLState->iXMLBufferPos == XMLState->iXMLBufferLen);
  1879. // find the thread with the smallest file position
  1880. for (i = 0; i < NumberProcesses+1; i++) {
  1881. OtherXMLState = PXMLThreadStates[i];
  1882. if (OtherXMLState->iXMLFileStart != -1 && OtherXMLState->iXMLFileStart < iMinFileStart) {
  1883. iMinFileStart = OtherXMLState->iXMLFileStart;
  1884. iMinThreadIndex = i;
  1885. }
  1886. }
  1887. if (iMinThreadIndex == ThreadState->XMLThreadIndex) {
  1888. // got lucky - this thread is the first one, so we don't need to do anything
  1889. XMLState->iXMLFileStart = -1;
  1890. XMLLeaveCriticalSection();
  1891. return;
  1892. }
  1893. // dump out all threads starting with ours - not sure if the order matters
  1894. // got the seek pos at the prev step
  1895. dwCurrentFilePos = iMinFileStart;
  1896. if (fXMLOutput) {
  1897. if (fseek(XMLFile, (long)dwCurrentFilePos, SEEK_SET) != -1) {
  1898. fwrite(XMLState->XMLBuffer, 1, XMLState->iXMLBufferLen, XMLFile);
  1899. }
  1900. }
  1901. dwCurrentFilePos += XMLState->iXMLBufferLen;
  1902. XMLState->iXMLFileStart = -1;
  1903. for (i = 0; i < NumberProcesses+1; i++) {
  1904. if (i != ThreadState->XMLThreadIndex) {
  1905. OtherXMLState = PXMLThreadStates[i];
  1906. if (OtherXMLState->iXMLFileStart != -1) {
  1907. OtherXMLState->iXMLFileStart = dwCurrentFilePos;
  1908. if (fXMLOutput) {
  1909. fwrite(OtherXMLState->XMLBuffer, 1, OtherXMLState->iXMLBufferLen, XMLFile);
  1910. }
  1911. dwCurrentFilePos += OtherXMLState->iXMLBufferLen;
  1912. }
  1913. }
  1914. }
  1915. // no need to write out the global tail because it didn't move
  1916. if (fXMLOutput) {
  1917. fflush(XMLFile);
  1918. }
  1919. XMLLeaveCriticalSection();
  1920. }
  1921. VOID
  1922. XMLThreadInitBuffer(PTHREADSTATE ThreadState)
  1923. {
  1924. PXMLTHREADSTATE XMLState;
  1925. if (!fXMLInitialized)
  1926. return;
  1927. XMLEnterCriticalSection();
  1928. XMLState = PXMLThreadStates[ThreadState->XMLThreadIndex];
  1929. if (XMLState->iXMLFileStart == -1) {
  1930. XMLState->iXMLFileStart = PXMLGlobalState->iXMLFileStart;
  1931. XMLState->iXMLBufferLen = 0;
  1932. XMLState->iXMLBufferPos = 0;
  1933. XMLState->fXMLInAction = FALSE;
  1934. }
  1935. XMLLeaveCriticalSection();
  1936. }
  1937. VOID _cdecl
  1938. XMLGlobalWrite(LPCSTR pszFmt, ...)
  1939. {
  1940. va_list va;
  1941. SIZE_T dwBufferLen;
  1942. SIZE_T dwCurrentFilePos;
  1943. UINT i;
  1944. if (!fXMLInitialized)
  1945. return;
  1946. XMLEnterCriticalSection();
  1947. for (i = 0; i < NumberProcesses+1; i++) {
  1948. if (PXMLThreadStates[i]->iXMLFileStart != -1) {
  1949. XMLLeaveCriticalSection();
  1950. return;
  1951. }
  1952. }
  1953. ZeroMemory(szXMLPrivateBuffer, sizeof(szXMLPrivateBuffer));
  1954. // build the string to write out
  1955. va_start(va, pszFmt);
  1956. _vsnprintf(szXMLPrivateBuffer, sizeof(szXMLPrivateBuffer)-1, pszFmt, va);
  1957. va_end(va);
  1958. dwBufferLen = strlen(szXMLPrivateBuffer);
  1959. // write it out
  1960. dwCurrentFilePos = PXMLGlobalState->iXMLFileStart;
  1961. if (fXMLOutput) {
  1962. if (fseek(XMLFile, (long)dwCurrentFilePos, SEEK_SET) != -1) {
  1963. fwrite(szXMLPrivateBuffer, 1, dwBufferLen, XMLFile);
  1964. }
  1965. }
  1966. dwCurrentFilePos += dwBufferLen;
  1967. // write out the global tail
  1968. if (fXMLOutput) {
  1969. fwrite(PXMLGlobalState->XMLBuffer, 1, PXMLGlobalState->iXMLBufferLen, XMLFile);
  1970. fflush(XMLFile);
  1971. }
  1972. // and update the tail position
  1973. PXMLGlobalState->iXMLFileStart += dwBufferLen;
  1974. XMLLeaveCriticalSection();
  1975. }
  1976. VOID _cdecl
  1977. XMLGlobalOpenTag(LPCSTR pszTag, LPCSTR pszFmt, ...)
  1978. {
  1979. va_list va;
  1980. SIZE_T dwBufferLen;
  1981. DWORD dwTagLen = strlen(pszTag);
  1982. SIZE_T dwCurrentFilePos;
  1983. UINT i;
  1984. if (!fXMLInitialized)
  1985. return;
  1986. XMLEnterCriticalSection();
  1987. for (i = 0; i < NumberProcesses+1; i++) {
  1988. PXMLTHREADSTATE OtherXMLState = PXMLThreadStates[i];
  1989. if (OtherXMLState->iXMLFileStart != -1) {
  1990. XMLLeaveCriticalSection();
  1991. return;
  1992. }
  1993. }
  1994. // build the string to write out
  1995. szXMLPrivateBuffer[0] = '<';
  1996. strcpy(szXMLPrivateBuffer + 1, pszTag);
  1997. if (pszFmt != NULL) {
  1998. va_start(va, pszFmt);
  1999. strcat(szXMLPrivateBuffer, " ");
  2000. vsprintf(szXMLPrivateBuffer + strlen(szXMLPrivateBuffer), pszFmt, va);
  2001. va_end(va);
  2002. }
  2003. strcat(szXMLPrivateBuffer, ">");
  2004. dwBufferLen = strlen(szXMLPrivateBuffer);
  2005. // insert the closing tag in the global tail
  2006. memmove(PXMLGlobalState->XMLBuffer + dwTagLen + 3, PXMLGlobalState->XMLBuffer, PXMLGlobalState->iXMLBufferLen+1); // include the null terminator
  2007. PXMLGlobalState->XMLBuffer[0] = '<';
  2008. PXMLGlobalState->XMLBuffer[1] = '/';
  2009. memcpy(PXMLGlobalState->XMLBuffer + 2, pszTag, dwTagLen);
  2010. PXMLGlobalState->XMLBuffer[dwTagLen + 2] = '>';
  2011. PXMLGlobalState->iXMLBufferLen += dwTagLen + 3;
  2012. // write out the string
  2013. dwCurrentFilePos = PXMLGlobalState->iXMLFileStart;
  2014. if (fXMLOutput) {
  2015. if (fseek(XMLFile, (long)dwCurrentFilePos, SEEK_SET) != -1) {
  2016. fwrite(szXMLPrivateBuffer, 1, dwBufferLen, XMLFile);
  2017. }
  2018. }
  2019. dwCurrentFilePos += dwBufferLen;
  2020. // put back the global tail
  2021. PXMLGlobalState->iXMLFileStart += dwBufferLen;
  2022. if (fXMLOutput) {
  2023. fwrite(PXMLGlobalState->XMLBuffer, 1, PXMLGlobalState->iXMLBufferLen, XMLFile);
  2024. fflush(XMLFile);
  2025. }
  2026. XMLLeaveCriticalSection();
  2027. }
  2028. VOID
  2029. XMLGlobalCloseTag()
  2030. {
  2031. char* psz;
  2032. SIZE_T dwTagLen;
  2033. if (!fXMLInitialized)
  2034. return;
  2035. XMLEnterCriticalSection();
  2036. if (PXMLGlobalState->iXMLBufferLen == 0) {
  2037. XMLLeaveCriticalSection();
  2038. return;
  2039. }
  2040. psz = PXMLGlobalState->XMLBuffer;
  2041. while (*psz != '>')
  2042. psz++;
  2043. psz++;
  2044. dwTagLen = psz - PXMLGlobalState->XMLBuffer;
  2045. memmove(PXMLGlobalState->XMLBuffer, psz, PXMLGlobalState->iXMLBufferLen - dwTagLen + 1); // include the null terminator
  2046. PXMLGlobalState->iXMLBufferLen -= dwTagLen;
  2047. PXMLGlobalState->iXMLFileStart += dwTagLen;
  2048. XMLLeaveCriticalSection();
  2049. }
  2050. VOID
  2051. XMLUpdateEndTag(BOOL fCompleted)
  2052. {
  2053. char* pszBuild;
  2054. char* pszEnd;
  2055. DWORD cbBufferLen;
  2056. time_t ltime;
  2057. if (!fXMLInitialized)
  2058. return;
  2059. XMLEnterCriticalSection();
  2060. pszBuild = strstr(PXMLGlobalState->XMLBuffer, "</BUILD>");
  2061. if (pszBuild == NULL) {
  2062. // no build tag is open yet
  2063. XMLLeaveCriticalSection();
  2064. return;
  2065. }
  2066. // remove the existing end tag
  2067. pszEnd = strstr(PXMLGlobalState->XMLBuffer, "<END ");
  2068. if (pszEnd != NULL) {
  2069. memmove(pszEnd, pszBuild, strlen(pszBuild)+1);
  2070. PXMLGlobalState->iXMLBufferLen -= (pszBuild - pszEnd);
  2071. pszBuild = pszEnd;
  2072. }
  2073. // generate the new end tag
  2074. time(&ltime);
  2075. sprintf(szXMLPrivateBuffer, "<END TIME=\"%s\" ELAPSED=\"%s\" PASSES=\"%d\" COMPLETED=\"%d\" ", ctime(&ltime), FormatElapsedTime(XMLStartTicks), NumberPasses, fCompleted);
  2076. strcat(szXMLPrivateBuffer, XMLBuildMetricsString(&RunningTotals));
  2077. strcat(szXMLPrivateBuffer, "/>");
  2078. cbBufferLen = strlen(szXMLPrivateBuffer);
  2079. // insert the new end tag into the buffer
  2080. memmove(pszBuild + cbBufferLen, pszBuild, strlen(pszBuild)+1);
  2081. memmove(pszBuild, szXMLPrivateBuffer, cbBufferLen);
  2082. PXMLGlobalState->iXMLBufferLen += cbBufferLen;
  2083. // write it out
  2084. if (fXMLOutput) {
  2085. if (fseek(XMLFile, (long)PXMLGlobalState->iXMLFileStart, SEEK_SET) != -1) {
  2086. fwrite(PXMLGlobalState->XMLBuffer, 1, PXMLGlobalState->iXMLBufferLen, XMLFile);
  2087. fflush(XMLFile);
  2088. }
  2089. }
  2090. XMLLeaveCriticalSection();
  2091. }
  2092. static char cEntity[5] = { "<&>\"'"};
  2093. static char* pszEntityEncoding[5] = {
  2094. "&lt;",
  2095. "&amp;",
  2096. "&gt;",
  2097. "&quot;",
  2098. "&apos;"
  2099. };
  2100. LPSTR
  2101. XMLEncodeBuiltInEntities(LPSTR pszString, DWORD cbStringSize)
  2102. {
  2103. DWORD cbStringLen = strlen(pszString);
  2104. char* psz = pszString;
  2105. DWORD cbExtraLen = 0;
  2106. int pos = 0;
  2107. char* pszTarget = NULL;
  2108. char* pszSource = NULL;
  2109. DWORD cbSourceLen = 0;
  2110. cbStringSize -= 1; // remove the null char
  2111. while ((pos = strcspn(psz, cEntity)) != strlen(psz)) {
  2112. cbExtraLen += strlen(pszEntityEncoding[strchr(cEntity, psz[pos])-cEntity])-1;
  2113. psz += pos+1;
  2114. }
  2115. if (cbExtraLen + cbStringLen > cbStringSize)
  2116. return NULL;
  2117. if (0 == cbExtraLen)
  2118. return pszString;
  2119. psz = pszString + cbStringSize - cbStringLen;
  2120. memmove(psz, pszString, cbStringLen+1);
  2121. pszTarget = pszString;
  2122. while ((pos = strcspn(psz, cEntity)) != strlen(psz)) {
  2123. memmove(pszTarget, psz, pos);
  2124. pszTarget += pos;
  2125. psz += pos;
  2126. pszSource = pszEntityEncoding[strchr(cEntity, *psz)-cEntity];
  2127. cbSourceLen = strlen(pszSource);
  2128. memmove(pszTarget, pszSource, cbSourceLen);
  2129. pszTarget += cbSourceLen;
  2130. psz++;
  2131. }
  2132. memmove(pszTarget, psz, pos);
  2133. pszTarget += pos;
  2134. *pszTarget = 0;
  2135. return pszString;
  2136. }
  2137. LPSTR
  2138. XMLEncodeBuiltInEntitiesCopy(LPSTR pszString, LPSTR pszTarget)
  2139. {
  2140. int pos = 0;
  2141. char* pszSource;
  2142. DWORD cbSourceLen;
  2143. char* psz = pszTarget;
  2144. while ((pos = strcspn(pszString, cEntity)) != strlen(pszString)) {
  2145. memmove(psz, pszString, pos);
  2146. psz += pos;
  2147. pszString += pos;
  2148. pszSource = pszEntityEncoding[strchr(cEntity, *pszString)-cEntity];
  2149. cbSourceLen = strlen(pszSource);
  2150. memmove(psz, pszSource, cbSourceLen);
  2151. psz += cbSourceLen;
  2152. pszString++;
  2153. }
  2154. memmove(psz, pszString, pos);
  2155. psz += pos;
  2156. *psz = 0;
  2157. return pszTarget;
  2158. }
  2159. BOOL
  2160. XMLScanBackTag(LPSTR pszEnd, LPSTR pszSentinel, LPSTR* ppszStart)
  2161. {
  2162. int nOpen = 0;
  2163. LPSTR pszClosing = NULL;
  2164. while (pszEnd != pszSentinel) {
  2165. --pszEnd;
  2166. if (*pszEnd == '>') {
  2167. pszClosing = pszEnd;
  2168. } else if (*pszEnd == '<') {
  2169. if (NULL == pszClosing) {
  2170. // found '<' before '>' - bad string
  2171. return FALSE;
  2172. }
  2173. if (*(pszEnd+1) == '/') {
  2174. if (*(pszClosing-1) == '/') {
  2175. // "</...../>" - bad string
  2176. return FALSE;
  2177. } else {
  2178. // "</....>" - closing tag
  2179. ++nOpen;
  2180. }
  2181. } else {
  2182. if (*(pszClosing-1) != '/') {
  2183. // "<....>" - opening tag
  2184. --nOpen;
  2185. }
  2186. // else
  2187. // "<..../>" - neutral tag
  2188. }
  2189. if (0 == nOpen) {
  2190. *ppszStart = pszEnd;
  2191. return TRUE;
  2192. }
  2193. }
  2194. }
  2195. return FALSE;
  2196. }
  2197. LPSTR
  2198. XMLBuildMetricsString(PBUILDMETRICS Metrics)
  2199. {
  2200. static char buffer[512];
  2201. buffer[0] = 0;
  2202. if (0 != Metrics->NumberCompiles)
  2203. sprintf(buffer + strlen(buffer), "FILESCOMPILED=\"%d\" ", Metrics->NumberCompiles);
  2204. if (0 != Metrics->NumberCompileErrors)
  2205. sprintf(buffer + strlen(buffer), "COMPILEERRORS=\"%d\" ", Metrics->NumberCompileErrors);
  2206. if (0 != Metrics->NumberCompileWarnings)
  2207. sprintf(buffer + strlen(buffer), "COMPILEWARNINGS=\"%d\" ", Metrics->NumberCompileWarnings);
  2208. if (0 != Metrics->NumberLibraries)
  2209. sprintf(buffer + strlen(buffer), "LIBRARIESBUILT=\"%d\" ", Metrics->NumberLibraries);
  2210. if (0 != Metrics->NumberLibraryErrors)
  2211. sprintf(buffer + strlen(buffer), "LIBRARYERRORS=\"%d\" ", Metrics->NumberLibraryErrors);
  2212. if (0 != Metrics->NumberLibraryWarnings)
  2213. sprintf(buffer + strlen(buffer), "LIBRARYWARNINGS=\"%d\" ", Metrics->NumberLibraryWarnings);
  2214. if (0 != Metrics->NumberLinks)
  2215. sprintf(buffer + strlen(buffer), "EXECUTABLESBUILT=\"%d\" ", Metrics->NumberLinks);
  2216. if (0 != Metrics->NumberLinkErrors)
  2217. sprintf(buffer + strlen(buffer), "LINKERRORS=\"%d\" ", Metrics->NumberLinkErrors);
  2218. if (0 != Metrics->NumberLinkWarnings)
  2219. sprintf(buffer + strlen(buffer), "LINKWARNINGS=\"%d\" ", Metrics->NumberLinkWarnings);
  2220. if (0 != Metrics->NumberBSCMakes)
  2221. sprintf(buffer + strlen(buffer), "BROWSERDBS=\"%d\" ", Metrics->NumberBSCMakes);
  2222. if (0 != Metrics->NumberBSCErrors)
  2223. sprintf(buffer + strlen(buffer), "BSCERRORS=\"%d\" ", Metrics->NumberBSCErrors);
  2224. if (0 != Metrics->NumberBSCWarnings)
  2225. sprintf(buffer + strlen(buffer), "BSCWARNINGS=\"%d\" ", Metrics->NumberBSCWarnings);
  2226. if (0 != Metrics->NumberVSToolErrors)
  2227. sprintf(buffer + strlen(buffer), "VSTOOLERRORS=\"%d\" ", Metrics->NumberVSToolErrors);
  2228. if (0 != Metrics->NumberVSToolWarnings)
  2229. sprintf(buffer + strlen(buffer), "VSTOOLWARNINGS=\"%d\" ", Metrics->NumberVSToolWarnings);
  2230. return buffer;
  2231. }
  2232. VOID _cdecl
  2233. XMLWriteFragmentFile(LPCSTR pszBaseFileName, LPCSTR pszFmt, ...)
  2234. {
  2235. va_list va;
  2236. FILE* PFile;
  2237. char szFileName[DB_MAX_PATH_LENGTH];
  2238. sprintf(szFileName, "%s\\%s_%s.xml", XMLFragmentDirectory, FormatCurrentDateTime(), pszBaseFileName);
  2239. XMLEnterCriticalSection();
  2240. va_start(va, pszFmt);
  2241. vsprintf(szXMLPrivateBuffer, pszFmt, va);
  2242. va_end(va);
  2243. PFile = fopen(szFileName, "wb");
  2244. if (PFile) {
  2245. fwrite(szXMLPrivateBuffer, 1, strlen(szXMLPrivateBuffer), PFile);
  2246. fclose(PFile);
  2247. }
  2248. XMLLeaveCriticalSection();
  2249. }
  2250. VOID _cdecl
  2251. XMLWriteDirFragmentFile(LPCSTR pszRelPath, PVOID pvBlock, SIZE_T cbCount)
  2252. {
  2253. FILE* PFile;
  2254. char* psz;
  2255. char szFileName[DB_MAX_PATH_LENGTH];
  2256. sprintf(szFileName, "%s\\%s_DIR_%s", XMLFragmentDirectory, FormatCurrentDateTime(), pszRelPath);
  2257. psz = szFileName+strlen(szFileName)-1;
  2258. if (*psz == '\\') {
  2259. *psz = 0;
  2260. }
  2261. strcat(szFileName, ".xml");
  2262. psz = szFileName+strlen(XMLFragmentDirectory)+1;
  2263. while (*psz) {
  2264. if (*psz == '\\') {
  2265. *psz = '_';
  2266. }
  2267. ++psz;
  2268. }
  2269. PFile = fopen(szFileName, "wb");
  2270. if (PFile) {
  2271. fwrite(pvBlock, 1, cbCount, PFile);
  2272. fclose(PFile);
  2273. }
  2274. }
  2275. VOID
  2276. AddBuildMetrics(PBUILDMETRICS TargetMetrics, PBUILDMETRICS SourceMetrics)
  2277. {
  2278. TargetMetrics->NumberCompileWarnings += SourceMetrics->NumberCompileWarnings;
  2279. TargetMetrics->NumberCompileErrors += SourceMetrics->NumberCompileErrors;
  2280. TargetMetrics->NumberCompiles += SourceMetrics->NumberCompiles;
  2281. TargetMetrics->NumberLibraries += SourceMetrics->NumberLibraries;
  2282. TargetMetrics->NumberLibraryWarnings += SourceMetrics->NumberLibraryWarnings;
  2283. TargetMetrics->NumberLibraryErrors += SourceMetrics->NumberLibraryErrors;
  2284. TargetMetrics->NumberLinks += SourceMetrics->NumberLinks;
  2285. TargetMetrics->NumberLinkWarnings += SourceMetrics->NumberLinkWarnings;
  2286. TargetMetrics->NumberLinkErrors += SourceMetrics->NumberLinkErrors;
  2287. TargetMetrics->NumberBSCMakes += SourceMetrics->NumberBSCMakes;
  2288. TargetMetrics->NumberBSCWarnings += SourceMetrics->NumberBSCWarnings;
  2289. TargetMetrics->NumberBSCErrors += SourceMetrics->NumberBSCErrors;
  2290. TargetMetrics->NumberVSToolErrors += SourceMetrics->NumberVSToolErrors;
  2291. TargetMetrics->NumberVSToolWarnings += SourceMetrics->NumberVSToolWarnings;
  2292. TargetMetrics->NumberDirActions += SourceMetrics->NumberDirActions;
  2293. TargetMetrics->NumberActWarnings += SourceMetrics->NumberActWarnings;
  2294. TargetMetrics->NumberActErrors += SourceMetrics->NumberActErrors;
  2295. }
  2296. VOID
  2297. XMLEnterCriticalSection()
  2298. {
  2299. if (fXMLInitialized) {
  2300. EnterCriticalSection(&XMLCriticalSection);
  2301. }
  2302. }
  2303. VOID
  2304. XMLLeaveCriticalSection()
  2305. {
  2306. if (fXMLInitialized) {
  2307. LeaveCriticalSection(&XMLCriticalSection);
  2308. }
  2309. }