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.

1818 lines
43 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. //
  14. //----------------------------------------------------------------------------
  15. #include "build.h"
  16. #if DBG
  17. //+---------------------------------------------------------------------------
  18. //
  19. // Memory Allocation/Deallocation functions
  20. //
  21. // These functions provide leak tracking on a debug build.
  22. //
  23. //----------------------------------------------------------------------------
  24. typedef struct _MEMHEADER {
  25. MemType mt;
  26. ULONG cbRequest;
  27. struct _MEMHEADER *pmhPrev;
  28. struct _MEMHEADER *pmhNext;
  29. } MEMHEADER;
  30. #define CBHEADER sizeof(MEMHEADER)
  31. #define CBTAIL sizeof(ULONG)
  32. char patternFree[CBTAIL] = { 'M', 'E', 'M', 'D' };
  33. char patternBusy[CBTAIL] = { 'm', 'e', 'm', 'd' };
  34. __inline MEMHEADER *
  35. GetHeader(VOID *pvblock)
  36. {
  37. return((MEMHEADER *) (pvblock) - 1);
  38. }
  39. __inline VOID *
  40. GetBlock(MEMHEADER *pmh)
  41. {
  42. return((VOID *) (pmh + 1));
  43. }
  44. __inline VOID
  45. FillTailBusy(LPSTR p)
  46. {
  47. memcpy(p, patternBusy, sizeof(patternBusy));
  48. }
  49. __inline VOID
  50. FillTailFree(LPSTR p)
  51. {
  52. memcpy(p, patternFree, sizeof(patternFree));
  53. }
  54. __inline BOOL
  55. CheckTail(LPSTR p)
  56. {
  57. return(memcmp(p, patternBusy, sizeof(patternBusy)) == 0);
  58. }
  59. typedef struct _MEMTAB {
  60. LPSTR pszType;
  61. ULONG cbAlloc;
  62. ULONG cAlloc;
  63. ULONG cbAllocTotal;
  64. ULONG cAllocTotal;
  65. MEMHEADER mh;
  66. } MEMTAB;
  67. ULONG cbAllocMax;
  68. ULONG cAllocMax;
  69. MEMTAB MemTab[] = {
  70. { "Totals", }, // MT_TOTALS
  71. { "Unknown", }, // MT_UNKNOWN
  72. { "ChildData", }, // MT_CHILDDATA
  73. { "CmdString", }, // MT_CMDSTRING
  74. { "DirDB", }, // MT_DIRDB
  75. { "DirSup", }, // MT_DIRSUP
  76. { "DirPath", }, // MT_DIRPATH
  77. { "DirString", }, // MT_DIRSTRING
  78. { "EventHandles", }, // MT_EVENTHANDLES
  79. { "FileDB", }, // MT_FILEDB
  80. { "FileReadBuf", }, // MT_FILEREADBUF
  81. { "FrbString", }, // MT_FRBSTRING
  82. { "IncludeDB", }, // MT_INCLUDEDB
  83. { "IoBuffer", }, // MT_IOBUFFER
  84. { "Macro", }, // MT_MACRO
  85. { "SourceDB", }, // MT_SOURCEDB
  86. { "Target", }, // MT_TARGET
  87. { "ThreadFilter", }, // MT_THREADFILTER
  88. { "ThreadHandles", }, // MT_THREADHANDLES
  89. { "ThreadState", }, // MT_THREADSTATE
  90. };
  91. #define MT_MAX (sizeof(MemTab)/sizeof(MemTab[0]))
  92. VOID
  93. InitMem(VOID)
  94. {
  95. MEMTAB *pmt;
  96. for (pmt = MemTab; pmt < &MemTab[MT_MAX]; pmt++) {
  97. assert(pmt->cAllocTotal == 0);
  98. pmt->mh.mt = MT_INVALID;
  99. pmt->mh.pmhNext = &pmt->mh;
  100. pmt->mh.pmhPrev = &pmt->mh;
  101. }
  102. }
  103. #else
  104. #define CBHEADER 0
  105. #define CBTAIL 0
  106. #endif
  107. //+---------------------------------------------------------------------------
  108. //
  109. // Function: AllocMem
  110. //
  111. // Synopsis: Allocate memory
  112. //
  113. // Arguments: [cb] -- Requested Size
  114. // [ppv] -- [out] allocated memory
  115. // [mt] -- Type of memory being allocated (MT_XXX)
  116. //
  117. //----------------------------------------------------------------------------
  118. VOID
  119. AllocMem(UINT cb, VOID **ppv, MemType mt)
  120. {
  121. *ppv = malloc(cb + CBHEADER + CBTAIL);
  122. if (*ppv == NULL) {
  123. BuildError("(Fatal Error) malloc(%u) failed\n", cb);
  124. exit(16);
  125. }
  126. #if DBG
  127. {
  128. MEMTAB *pmt;
  129. MEMHEADER *pmh;
  130. pmh = *ppv;
  131. *ppv = GetBlock(pmh);
  132. if (mt >= MT_MAX) {
  133. mt = MT_UNKNOWN;
  134. }
  135. pmt = &MemTab[MT_TOTALS];
  136. if (pmt->cAllocTotal == 0) {
  137. InitMem();
  138. }
  139. pmt->cAlloc++;
  140. pmt->cAllocTotal++;
  141. pmt->cbAlloc += cb;
  142. pmt->cbAllocTotal += cb;
  143. if (cbAllocMax < pmt->cbAlloc) {
  144. cbAllocMax = pmt->cbAlloc;
  145. }
  146. if (cAllocMax < pmt->cAlloc) {
  147. cAllocMax = pmt->cAlloc;
  148. }
  149. pmt = &MemTab[mt];
  150. pmt->cAlloc++;
  151. pmt->cAllocTotal++;
  152. pmt->cbAlloc += cb;
  153. pmt->cbAllocTotal += cb;
  154. pmh->mt = mt;
  155. pmh->cbRequest = cb;
  156. pmh->pmhNext = pmt->mh.pmhNext;
  157. pmt->mh.pmhNext = pmh;
  158. pmh->pmhPrev = pmh->pmhNext->pmhPrev;
  159. pmh->pmhNext->pmhPrev = pmh;
  160. FillTailBusy((char *) *ppv + cb);
  161. if (DEBUG_4 && DEBUG_1) {
  162. BuildError("AllocMem(%d, mt=%s) -> %lx\n", cb, pmt->pszType, *ppv);
  163. }
  164. }
  165. #endif
  166. }
  167. //+---------------------------------------------------------------------------
  168. //
  169. // Function: FreeMem
  170. //
  171. // Synopsis: Free memory allocated by AllocMem
  172. //
  173. // Arguments: [ppv] -- Memory pointer
  174. // [mt] -- Type of memory (MT_XXX)
  175. //
  176. // Notes: Sets the memory pointer to null after freeing it.
  177. //
  178. //----------------------------------------------------------------------------
  179. VOID
  180. FreeMem(VOID **ppv, MemType mt)
  181. {
  182. assert(*ppv != NULL);
  183. #if DBG
  184. {
  185. MEMTAB *pmt;
  186. MEMHEADER *pmh;
  187. pmh = GetHeader(*ppv);
  188. if (mt == MT_DIRDB ||
  189. mt == MT_FILEDB ||
  190. mt == MT_INCLUDEDB ||
  191. mt == MT_SOURCEDB) {
  192. SigCheck(assert(((DIRREC *) (*ppv))->Sig == 0));
  193. }
  194. if (mt >= MT_MAX) {
  195. mt = MT_UNKNOWN;
  196. }
  197. pmt = &MemTab[MT_TOTALS];
  198. pmt->cAlloc--;
  199. pmt->cbAlloc -= pmh->cbRequest;
  200. pmt = &MemTab[mt];
  201. pmt->cAlloc--;
  202. pmt->cbAlloc -= pmh->cbRequest;
  203. if (DEBUG_4 && DEBUG_1) {
  204. BuildError(
  205. "FreeMem(%d, mt=%s) <- %lx\n",
  206. pmh->cbRequest,
  207. pmt->pszType,
  208. *ppv);
  209. }
  210. assert(CheckTail((char *) *ppv + pmh->cbRequest));
  211. FillTailFree((char *) *ppv + pmh->cbRequest);
  212. assert(mt == pmh->mt);
  213. pmh->pmhNext->pmhPrev = pmh->pmhPrev;
  214. pmh->pmhPrev->pmhNext = pmh->pmhNext;
  215. pmh->pmhNext = pmh->pmhPrev = NULL;
  216. pmh->mt = MT_INVALID;
  217. *ppv = pmh;
  218. }
  219. #endif
  220. free(*ppv);
  221. *ppv = NULL;
  222. }
  223. //+---------------------------------------------------------------------------
  224. //
  225. // Function: ReportMemoryUsage
  226. //
  227. // Synopsis: Report current memory usage (if any) on a debug build. If
  228. // called just before termination, memory leaks will be
  229. // displayed.
  230. //
  231. // Arguments: (none)
  232. //
  233. //----------------------------------------------------------------------------
  234. VOID
  235. ReportMemoryUsage(VOID)
  236. {
  237. #if DBG
  238. MEMTAB *pmt;
  239. UINT i;
  240. if (DEBUG_1) {
  241. BuildErrorRaw(
  242. "Maximum memory usage: %5lx bytes in %4lx blocks\n",
  243. cbAllocMax,
  244. cAllocMax);
  245. for (pmt = MemTab; pmt < &MemTab[MT_MAX]; pmt++) {
  246. BuildErrorRaw(
  247. "%5lx bytes in %4lx blocks, %5lx bytes in %4lx blocks Total (%s)\n",
  248. pmt->cbAlloc,
  249. pmt->cAlloc,
  250. pmt->cbAllocTotal,
  251. pmt->cAllocTotal,
  252. pmt->pszType);
  253. }
  254. }
  255. FreeMem(&BigBuf, MT_IOBUFFER);
  256. if (fDebug & 8) {
  257. PrintAllDirs();
  258. }
  259. FreeAllDirs();
  260. if (DEBUG_1 || MemTab[MT_TOTALS].cbAlloc != 0) {
  261. BuildErrorRaw(szNewLine);
  262. if (MemTab[MT_TOTALS].cbAlloc != 0) {
  263. BuildError("Internal memory leaks detected:\n");
  264. }
  265. for (pmt = MemTab; pmt < &MemTab[MT_MAX]; pmt++) {
  266. BuildErrorRaw(
  267. "%5lx bytes in %4lx blocks, %5lx bytes in %4lx blocks Total (%s)\n",
  268. pmt->cbAlloc,
  269. pmt->cAlloc,
  270. pmt->cbAllocTotal,
  271. pmt->cAllocTotal,
  272. pmt->pszType);
  273. }
  274. }
  275. #endif
  276. }
  277. //+---------------------------------------------------------------------------
  278. //
  279. // Function: MyOpenFile
  280. //
  281. // Synopsis: Open a file
  282. //
  283. //----------------------------------------------------------------------------
  284. BOOL
  285. MyOpenFile(
  286. LPSTR DirName,
  287. LPSTR FileName,
  288. LPSTR Access,
  289. FILE **ppf,
  290. BOOL BufferedIO)
  291. {
  292. char path[ DB_MAX_PATH_LENGTH * 2 + 1]; // ensure we have enough space for "DirName" + "\\" + "FileName"
  293. strcpy(path, DirName);
  294. if (path[0] != '\0') {
  295. strcat(path, "\\");
  296. }
  297. strcat(path, FileName);
  298. *ppf = fopen( path, Access );
  299. if (*ppf == NULL) {
  300. if (*Access == 'w') {
  301. BuildError("%s: create file failed\n", path);
  302. }
  303. return(FALSE);
  304. }
  305. if (!BufferedIO) {
  306. setvbuf(*ppf, NULL, _IONBF, 0); // Clear buffering on the stream.
  307. }
  308. return(TRUE);
  309. }
  310. typedef struct _FILEREADBUF {
  311. struct _FILEREADBUF *pfrbNext;
  312. LPSTR pszFile;
  313. LPSTR pbBuffer;
  314. LPSTR pbNext;
  315. UINT cbBuf;
  316. UINT cbBuffer;
  317. UINT cbTotal;
  318. UINT cbFile;
  319. USHORT cLine;
  320. USHORT cNull;
  321. ULONG DateTime;
  322. FILE *pf;
  323. LPSTR pszCommentToEOL;
  324. size_t cbCommentToEOL;
  325. BOOLEAN fEof;
  326. BOOLEAN fOpen;
  327. BOOLEAN fMakefile;
  328. } FILEREADBUF;
  329. static FILEREADBUF Frb;
  330. char achzeros[16];
  331. //+---------------------------------------------------------------------------
  332. //
  333. // Function: OpenFilePush
  334. //
  335. //----------------------------------------------------------------------------
  336. BOOL
  337. OpenFilePush(
  338. LPSTR pszdir,
  339. LPSTR pszfile,
  340. LPSTR pszCommentToEOL,
  341. FILE **ppf
  342. )
  343. {
  344. FILEREADBUF *pfrb;
  345. if (Frb.fOpen) {
  346. AllocMem(sizeof(*pfrb), &pfrb, MT_FILEREADBUF);
  347. memcpy(pfrb, &Frb, sizeof(*pfrb));
  348. memset(&Frb, 0, sizeof(Frb));
  349. Frb.pfrbNext = pfrb;
  350. } else {
  351. pfrb = NULL;
  352. }
  353. if (!SetupReadFile(
  354. pszdir,
  355. pszfile,
  356. pszCommentToEOL,
  357. ppf)) {
  358. if (pfrb != NULL) {
  359. memcpy(&Frb, pfrb, sizeof(*pfrb));
  360. FreeMem(&pfrb, MT_FILEREADBUF);
  361. }
  362. return FALSE;
  363. }
  364. return TRUE;
  365. }
  366. //+---------------------------------------------------------------------------
  367. //
  368. // Function: ReadFilePush
  369. //
  370. //----------------------------------------------------------------------------
  371. LPSTR
  372. ReadFilePush(LPSTR pszfile)
  373. {
  374. FILE *pf;
  375. assert(Frb.fOpen);
  376. OpenFilePush(IsFullPath(pszfile) ? "" : Frb.pszFile, pszfile,
  377. Frb.pszCommentToEOL, &pf);
  378. return(ReadLine(Frb.pf));
  379. }
  380. //+---------------------------------------------------------------------------
  381. //
  382. // Function: ReadFilePop
  383. //
  384. //----------------------------------------------------------------------------
  385. LPSTR
  386. ReadFilePop(VOID)
  387. {
  388. if (Frb.pfrbNext == NULL) {
  389. return(NULL);
  390. }
  391. CloseReadFile(NULL);
  392. return(ReadLine(Frb.pf));
  393. }
  394. //+---------------------------------------------------------------------------
  395. //
  396. // Function: ReadBuf
  397. //
  398. //----------------------------------------------------------------------------
  399. BOOL
  400. ReadBuf(FILE *pf)
  401. {
  402. LPSTR p, p2;
  403. assert(pf == Frb.pf);
  404. assert(!Frb.fEof);
  405. Frb.pbNext = Frb.pbBuffer;
  406. Frb.cbBuf = fread(Frb.pbBuffer, 1, Frb.cbBuffer - 1, Frb.pf);
  407. if (Frb.cbBuf == 0) {
  408. Frb.fEof = TRUE; // no more to read
  409. return(FALSE);
  410. }
  411. if (Frb.cbTotal == 0 &&
  412. Frb.cbBuf > sizeof(achzeros) &&
  413. memcmp(Frb.pbBuffer, achzeros, sizeof(achzeros)) == 0) {
  414. BuildError("ignoring binary file\n");
  415. Frb.fEof = TRUE;
  416. return(FALSE);
  417. }
  418. p = &Frb.pbBuffer[Frb.cbBuf - 1];
  419. if (Frb.cbTotal + Frb.cbBuf < Frb.cbFile) {
  420. do {
  421. while (p > Frb.pbBuffer && *p != '\n') {
  422. p--;
  423. }
  424. p2 = p; // save end of last complete line
  425. if (p > Frb.pbBuffer && *p == '\n') {
  426. p--;
  427. if (p > Frb.pbBuffer && *p == '\r') {
  428. p--;
  429. }
  430. while (p > Frb.pbBuffer && (*p == '\t' || *p == ' ')) {
  431. p--;
  432. }
  433. }
  434. } while (*p == '\\');
  435. if (p == Frb.pbBuffer) {
  436. BuildError("(Fatal Error) too many continuation lines\n");
  437. exit(8);
  438. }
  439. p = p2; // restore end of last complete line
  440. Frb.cbBuf = (UINT)(p - Frb.pbBuffer + 1);
  441. } else {
  442. Frb.fEof = TRUE; // no more to read
  443. }
  444. p[1] = '\0';
  445. Frb.cbTotal += Frb.cbBuf;
  446. return(TRUE);
  447. }
  448. //+---------------------------------------------------------------------------
  449. //
  450. // Function: IsNmakeInclude
  451. //
  452. //----------------------------------------------------------------------------
  453. LPSTR
  454. IsNmakeInclude(LPSTR pinc)
  455. {
  456. static char szInclude[] = "include";
  457. LPSTR pnew, p;
  458. while (*pinc == ' ') {
  459. pinc++;
  460. }
  461. if (_strnicmp(pinc, szInclude, sizeof(szInclude) - 1) == 0 &&
  462. pinc[sizeof(szInclude) - 1] == ' ') {
  463. pnew = NULL;
  464. pinc += sizeof(szInclude);
  465. while (*pinc == ' ') {
  466. pinc++;
  467. }
  468. if (MakeMacroString(&pnew, pinc)) {
  469. p = strchr(pnew, ' ');
  470. if (p != NULL) {
  471. *p = '\0';
  472. }
  473. return(pnew);
  474. }
  475. }
  476. return(NULL);
  477. }
  478. //+---------------------------------------------------------------------------
  479. //
  480. // Function: ReadLine
  481. //
  482. // Synopsis: Read a line from the input file.
  483. //
  484. // Arguments: [pf] -- File to read from
  485. //
  486. // Returns: Line read from file
  487. //
  488. // Notes: ReadLine returns a canonical line from the input file.
  489. // This involves:
  490. //
  491. // 1) Converting tab to spaces. Various editors/users change
  492. // tabbing.
  493. // 2) Uniformly terminate lines. Some editors drop CR in
  494. // CRLF or add extras.
  495. // 3) Handle file-type-specific continuations.
  496. //
  497. //----------------------------------------------------------------------------
  498. LPSTR
  499. ReadLine(FILE *pf)
  500. {
  501. LPSTR p, pend, pline;
  502. LPSTR pcont;
  503. UCHAR chComment0 = Frb.pszCommentToEOL[0];
  504. BOOL fInComment, fWhiteSpace;
  505. assert(pf == Frb.pf || (pf != NULL && Frb.pfrbNext != NULL));
  506. if (Frb.cbBuf == 0) {
  507. if (Frb.fEof) {
  508. return(ReadFilePop());
  509. }
  510. if (fseek(Frb.pf, Frb.cbTotal, SEEK_SET) == -1) {
  511. return(ReadFilePop());
  512. }
  513. if (!ReadBuf(Frb.pf)) {
  514. return(ReadFilePop());
  515. }
  516. }
  517. pline = p = Frb.pbNext;
  518. pend = &p[Frb.cbBuf];
  519. pcont = NULL;
  520. // scan through line forward
  521. fInComment = FALSE;
  522. while (p < pend) {
  523. switch (*p) {
  524. case '\n': // Are we at an end of line?
  525. if (*p == '\n') {
  526. Frb.cLine++;
  527. }
  528. // FALL THROUGH
  529. case '\0':
  530. if (pcont == NULL) {
  531. goto eol; // bail out if single line
  532. } // else combine multiple lines...
  533. *pcont = ' '; // remove continuation char
  534. pcont = NULL; // eat only one line per continuation
  535. // We've seen a continuation char with whitespace following.
  536. // If we're in a comment then we complain and break anyway.
  537. if (fInComment) {
  538. if (DEBUG_1) {
  539. BuildError ("continued line is commented out\n");
  540. }
  541. goto eol; // bail out - ignore continuation
  542. }
  543. *p = ' '; // join the lines with blanks
  544. break;
  545. case '\\':
  546. pcont = p; // remember continuation character
  547. break;
  548. case ' ':
  549. break;
  550. case '\t':
  551. case '\r':
  552. *p = ' ';
  553. break;
  554. default:
  555. // See if the character we're examining begins the
  556. // comment-to-EOL string.
  557. if (*p == chComment0 &&
  558. !strncmp(p, Frb.pszCommentToEOL, Frb.cbCommentToEOL)) {
  559. fInComment = TRUE;
  560. }
  561. pcont = NULL; // not a continuation character
  562. break;
  563. }
  564. p++;
  565. }
  566. eol:
  567. assert(Frb.cbBuf >= (UINT) (p - Frb.pbNext));
  568. Frb.cbBuf -= (UINT)(p - Frb.pbNext);
  569. Frb.pbNext = p;
  570. if (pcont != NULL) {
  571. *pcont = ' '; // file ended with backslash...
  572. }
  573. assert(*p == '\0' || *p == '\n');
  574. if (p < pend) {
  575. if (*p == '\0') {
  576. if (Frb.cNull++ == 0) {
  577. BuildError("null byte at offset %lx\n",
  578. Frb.cbTotal - Frb.cbBuf + p - Frb.pbNext);
  579. }
  580. }
  581. *p = '\0'; // terminate line
  582. assert(Frb.cbBuf >= 1);
  583. Frb.cbBuf--; // account for newline (or null)
  584. Frb.pbNext++;
  585. } else {
  586. assert(p == pend && *p == '\0');
  587. if (*pline == 'Z' - 64 && p == &pline[1] && Frb.cbBuf == 0) {
  588. pline = NULL; // found CTL-Z at end of file
  589. } else {
  590. // BuildError( "last line incomplete\n");
  591. }
  592. }
  593. fWhiteSpace = FALSE;
  594. if (pline != NULL) {
  595. while (*pline == ' ') {
  596. pline++; // skip leading whitespace
  597. fWhiteSpace = TRUE;
  598. }
  599. if (*p != '\0') {
  600. BuildError( "\"*p != '\\0'\" at offset %lx\n",
  601. Frb.cbTotal - Frb.cbBuf + p - Frb.pbNext);
  602. BuildError(
  603. "pline=%x(%s) p=%x(%s)\n",
  604. pline,
  605. pline,
  606. p,
  607. p,
  608. Frb.cbTotal - Frb.cbBuf + p - Frb.pbNext);
  609. }
  610. assert(*p == '\0');
  611. while (p > pline && *--p == ' ') {
  612. *p = '\0'; // truncate trailing whitespace
  613. }
  614. }
  615. if (pline == NULL) {
  616. return(ReadFilePop());
  617. }
  618. if (Frb.fMakefile && !fWhiteSpace && *pline == '!') {
  619. p = IsNmakeInclude(pline + 1);
  620. if (p != NULL) {
  621. if (Frb.fMakefile && DEBUG_4) {
  622. BuildError("!include(%s)\n", p);
  623. }
  624. pline = ReadFilePush(p);
  625. FreeMem(&p, MT_DIRSTRING);
  626. }
  627. }
  628. return(pline);
  629. }
  630. //+---------------------------------------------------------------------------
  631. //
  632. // Function: SetupReadFile
  633. //
  634. // Synopsis: Open a file and prepare to read from it.
  635. //
  636. // Arguments: [pszdir] -- Directory name
  637. // [pszfile] -- Filename
  638. // [pszCommentToEOL] -- Comment to EOL string
  639. // [ppf] -- [out] Open file handle
  640. //
  641. // Returns: TRUE if opened successfully
  642. //
  643. // Notes: This function, in order to minimize disk hits, reads the
  644. // entire file into a buffer, which is then used by the ReadLine
  645. // function.
  646. //
  647. //----------------------------------------------------------------------------
  648. BOOL
  649. SetupReadFile(
  650. LPSTR pszdir,
  651. LPSTR pszfile,
  652. LPSTR pszCommentToEOL,
  653. FILE **ppf
  654. )
  655. {
  656. char path[DB_MAX_PATH_LENGTH];
  657. assert(!Frb.fOpen);
  658. assert(Frb.pf == NULL);
  659. assert(Frb.pszFile == NULL);
  660. Frb.fMakefile = strcmp(pszCommentToEOL, "#") == 0;
  661. Frb.DateTime = 0;
  662. strcpy(path, pszdir);
  663. if (Frb.pfrbNext != NULL) { // if a nested open
  664. LPSTR p;
  665. if (Frb.fMakefile && !IsFullPath(pszfile)) {
  666. // nmake handles relative includes in makefiles by
  667. // attempting to locate the file relative to each makefile
  668. // in the complete include chain.
  669. FILEREADBUF *pfrb;
  670. for (pfrb = Frb.pfrbNext; pfrb != NULL; pfrb = pfrb->pfrbNext) {
  671. assert(pfrb->pszFile != NULL);
  672. strcpy(path, pfrb->pszFile);
  673. p = strrchr(path, '\\');
  674. if (p != NULL) {
  675. *p = '\0';
  676. }
  677. if (ProbeFile(path, pszfile) != -1) {
  678. break;
  679. }
  680. }
  681. if (pfrb == NULL) {
  682. // Unable to find file anywhere along path.
  683. return FALSE;
  684. }
  685. } else {
  686. p = strrchr(path, '\\');
  687. if (p != NULL) {
  688. *p = '\0';
  689. }
  690. }
  691. }
  692. if (!MyOpenFile(path, pszfile, "rb", ppf, TRUE)) {
  693. *ppf = NULL;
  694. return(FALSE);
  695. }
  696. if (Frb.fMakefile) {
  697. Frb.DateTime = (*pDateTimeFile)(path, pszfile);
  698. }
  699. Frb.cLine = 0;
  700. Frb.cNull = 0;
  701. Frb.cbTotal = 0;
  702. Frb.pf = *ppf;
  703. Frb.fEof = FALSE;
  704. Frb.pszCommentToEOL = pszCommentToEOL;
  705. Frb.cbCommentToEOL = strlen(pszCommentToEOL);
  706. if (fseek(Frb.pf, 0L, SEEK_END) != -1) {
  707. Frb.cbFile = ftell(Frb.pf);
  708. if (fseek(Frb.pf, 0L, SEEK_SET) == -1) {
  709. Frb.cbFile = 0;
  710. }
  711. } else {
  712. Frb.cbFile = 0;
  713. }
  714. Frb.cbBuffer = BigBufSize;
  715. if (Frb.pfrbNext != NULL) {
  716. if (Frb.cbBuffer > Frb.cbFile + 1) {
  717. Frb.cbBuffer = Frb.cbFile + 1;
  718. }
  719. AllocMem(Frb.cbBuffer, &Frb.pbBuffer, MT_IOBUFFER);
  720. } else {
  721. Frb.pbBuffer = BigBuf;
  722. }
  723. if (!ReadBuf(Frb.pf)) {
  724. fclose(Frb.pf);
  725. Frb.pf = *ppf = NULL;
  726. if (Frb.pfrbNext != NULL) {
  727. FreeMem(&Frb.pbBuffer, MT_IOBUFFER);
  728. }
  729. return(FALSE); // zero byte file
  730. }
  731. if (path[0] != '\0') {
  732. strcat(path, "\\");
  733. }
  734. strcat(path, pszfile);
  735. MakeString(&Frb.pszFile, path, TRUE, MT_FRBSTRING);
  736. Frb.fOpen = TRUE;
  737. if (Frb.fMakefile && DEBUG_4) {
  738. BuildError(
  739. "Opening file: cbFile=%lu cbBuf=%lu\n",
  740. Frb.cbTotal,
  741. Frb.cbBuffer);
  742. }
  743. return(TRUE);
  744. }
  745. //+---------------------------------------------------------------------------
  746. //
  747. // Function: CloseReadFile
  748. //
  749. // Synopsis: Close the open file buffer.
  750. //
  751. // Arguments: [pcline] -- [out] Count of lines in file.
  752. //
  753. // Returns: Timestamp of file
  754. //
  755. //----------------------------------------------------------------------------
  756. ULONG
  757. CloseReadFile(
  758. UINT *pcline
  759. )
  760. {
  761. assert(Frb.fOpen);
  762. assert(Frb.pf != NULL);
  763. assert(Frb.pszFile != NULL);
  764. if (Frb.fMakefile && DEBUG_4) {
  765. BuildError("Closing file\n");
  766. }
  767. if (Frb.cNull > 1) {
  768. BuildError("%hu null bytes in file\n", Frb.cNull);
  769. }
  770. fclose(Frb.pf);
  771. Frb.fOpen = FALSE;
  772. Frb.pf = NULL;
  773. FreeString(&Frb.pszFile, MT_FRBSTRING);
  774. if (Frb.pfrbNext != NULL) {
  775. FILEREADBUF *pfrb;
  776. FreeMem(&Frb.pbBuffer, MT_IOBUFFER);
  777. pfrb = Frb.pfrbNext;
  778. if (pfrb->DateTime < Frb.DateTime) {
  779. pfrb->DateTime = Frb.DateTime; // propagate subordinate timestamp
  780. }
  781. memcpy(&Frb, pfrb, sizeof(*pfrb));
  782. FreeMem(&pfrb, MT_FILEREADBUF);
  783. }
  784. if (pcline != NULL) {
  785. *pcline = Frb.cLine;
  786. }
  787. return(Frb.DateTime);
  788. }
  789. //+---------------------------------------------------------------------------
  790. //
  791. // Function: ProbeFile
  792. //
  793. // Synopsis: Determine if a file exists
  794. //
  795. //----------------------------------------------------------------------------
  796. UINT
  797. ProbeFile(
  798. LPSTR DirName,
  799. LPSTR FileName
  800. )
  801. {
  802. char path[ DB_MAX_PATH_LENGTH ];
  803. if (DirName != NULL) {
  804. sprintf(path, "%s\\%s", DirName, FileName);
  805. FileName = path;
  806. }
  807. return(GetFileAttributes(FileName));
  808. }
  809. //+---------------------------------------------------------------------------
  810. //
  811. // Function: EnsureDirectoriesExist
  812. //
  813. // Synopsis: Ensures the given directory exists. If the path contains
  814. // an asterisk, it will be expanded into all current machine
  815. // target names.
  816. //
  817. // Arguments: [DirName] -- Name of directory to create if necessary
  818. //
  819. // Returns: FALSE if the directory could not be created, TRUE if it
  820. // already exists or it could be created.
  821. //
  822. //----------------------------------------------------------------------------
  823. BOOL
  824. EnsureDirectoriesExist(
  825. LPSTR DirName
  826. )
  827. {
  828. char path[ DB_MAX_PATH_LENGTH ];
  829. char *p;
  830. UINT i;
  831. if (!DirName || DirName[0] == '\0')
  832. return FALSE;
  833. for (i = 0; i < CountTargetMachines; i++) {
  834. // Replace '*' with appropriate name
  835. ExpandObjAsterisk(
  836. path,
  837. DirName,
  838. TargetMachines[i]->ObjectDirectory);
  839. if (ProbeFile(NULL, path) != -1) {
  840. continue;
  841. }
  842. p = path;
  843. while (TRUE) {
  844. p = strchr(p, '\\');
  845. if (p != NULL) {
  846. *p = '\0';
  847. }
  848. if (!CreateBuildDirectory(path)) {
  849. return FALSE;
  850. }
  851. if (p == NULL) {
  852. break;
  853. }
  854. *p++ = '\\';
  855. }
  856. }
  857. return TRUE;
  858. }
  859. //+---------------------------------------------------------------------------
  860. //
  861. // Function: DateTimeFile
  862. //
  863. // Synopsis: Get the timestamp on a file
  864. //
  865. //----------------------------------------------------------------------------
  866. ULONG
  867. DateTimeFile(
  868. LPSTR DirName,
  869. LPSTR FileName
  870. )
  871. {
  872. char path[ DB_MAX_PATH_LENGTH ];
  873. WIN32_FIND_DATA FindFileData;
  874. HDIR FindHandle;
  875. ULONG FileDateTime;
  876. if (DirName == NULL || DirName[0] == '\0') {
  877. FindHandle = FindFirstFile( FileName, &FindFileData );
  878. } else {
  879. sprintf( path, "%s\\%s", DirName, FileName );
  880. FindHandle = FindFirstFile( path, &FindFileData );
  881. }
  882. if (FindHandle == (HDIR)INVALID_HANDLE_VALUE) {
  883. return( 0L );
  884. } else {
  885. FindClose( FindHandle );
  886. FileDateTime = 0L;
  887. FileTimeToDosDateTime( &FindFileData.ftLastWriteTime,
  888. ((LPWORD)&FileDateTime)+1,
  889. (LPWORD)&FileDateTime
  890. );
  891. return( FileDateTime );
  892. }
  893. }
  894. //+---------------------------------------------------------------------------
  895. //
  896. // Function: DateTimeFile2
  897. //
  898. // Synopsis: Get the timestamp on a file using the new GetFileAttributesExA
  899. //
  900. //----------------------------------------------------------------------------
  901. ULONG
  902. DateTimeFile2(
  903. LPSTR DirName,
  904. LPSTR FileName
  905. )
  906. {
  907. char path[ DB_MAX_PATH_LENGTH ];
  908. WIN32_FILE_ATTRIBUTE_DATA FileData;
  909. ULONG FileDateTime;
  910. BOOL rc;
  911. if (DirName == NULL || DirName[0] == '\0') {
  912. strcpy( path, FileName );
  913. } else {
  914. sprintf( path, "%s\\%s", DirName, FileName );
  915. }
  916. rc = (*pGetFileAttributesExA) (path, GetFileExInfoStandard, (LPVOID)&FileData);
  917. if (!rc) {
  918. return( 0L );
  919. } else {
  920. FILETIME ftSystemTime;
  921. SYSTEMTIME stSystemTime;
  922. unsigned __int64 ui64Local, ui64File;
  923. GetSystemTime(&stSystemTime);
  924. SystemTimeToFileTime(&stSystemTime, &ftSystemTime);
  925. ui64Local = (((unsigned __int64) ftSystemTime.dwHighDateTime) << 32) +
  926. (unsigned __int64) ftSystemTime.dwLowDateTime;
  927. ui64File = (((unsigned __int64) FileData.ftLastWriteTime.dwHighDateTime) << 32) +
  928. (unsigned __int64) FileData.ftLastWriteTime.dwLowDateTime;
  929. // Take into account that file times may have two second intervals (0x989680 = 1 second)
  930. // for FAT drives.
  931. if (ui64File > (ui64Local + (0x989680*2))) {
  932. BuildError("ERROR - \"%s\" file time is in the future.\n", path);
  933. }
  934. FileDateTime = 0L;
  935. FileTimeToDosDateTime( &FileData.ftLastWriteTime,
  936. ((LPWORD)&FileDateTime)+1,
  937. (LPWORD)&FileDateTime
  938. );
  939. return( FileDateTime );
  940. }
  941. }
  942. //+---------------------------------------------------------------------------
  943. //
  944. // Function: DeleteSingleFile
  945. //
  946. // Synopsis: Delete the given file
  947. //
  948. //----------------------------------------------------------------------------
  949. BOOL
  950. DeleteSingleFile(
  951. LPSTR DirName,
  952. LPSTR FileName,
  953. BOOL QuietFlag
  954. )
  955. {
  956. char path[ DB_MAX_PATH_LENGTH * 2 + 1]; // ensure we have enough space for "DirName" + "\\" + "FileName"
  957. if (DirName) {
  958. sprintf( path, "%s\\%s", DirName, FileName );
  959. }
  960. else {
  961. strcpy( path, FileName );
  962. }
  963. if (!QuietFlag && fQuery) {
  964. BuildMsgRaw("'erase %s'\n", path);
  965. return( TRUE );
  966. }
  967. return( DeleteFile( path ) );
  968. }
  969. //+---------------------------------------------------------------------------
  970. //
  971. // Function: DeleteMultipleFiles
  972. //
  973. // Synopsis: Delete one or more files matching a pattern.
  974. //
  975. //----------------------------------------------------------------------------
  976. BOOL
  977. DeleteMultipleFiles(
  978. LPSTR DirName,
  979. LPSTR FilePattern
  980. )
  981. {
  982. char path[ DB_MAX_PATH_LENGTH ];
  983. WIN32_FIND_DATA FindFileData;
  984. HDIR FindHandle;
  985. sprintf( path, "%s\\%s", DirName, FilePattern );
  986. if (fQuery) {
  987. BuildMsgRaw("'erase %s'\n", path);
  988. return( TRUE );
  989. }
  990. FindHandle = FindFirstFile( path, &FindFileData );
  991. if (FindHandle == (HDIR)INVALID_HANDLE_VALUE) {
  992. return( FALSE );
  993. }
  994. do {
  995. if (!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  996. DeleteSingleFile( DirName, FindFileData.cFileName, TRUE );
  997. }
  998. }
  999. while (FindNextFile( FindHandle, &FindFileData ));
  1000. FindClose( FindHandle );
  1001. return( TRUE );
  1002. }
  1003. //+---------------------------------------------------------------------------
  1004. //
  1005. // Function: CloseOrDeleteFile
  1006. //
  1007. //----------------------------------------------------------------------------
  1008. BOOL
  1009. CloseOrDeleteFile(
  1010. FILE **ppf,
  1011. LPSTR DirName,
  1012. LPSTR FileName,
  1013. ULONG SizeThreshold
  1014. )
  1015. {
  1016. ULONG Temp;
  1017. if (*ppf == NULL) {
  1018. return TRUE;
  1019. }
  1020. Temp = ftell( *ppf );
  1021. fclose( *ppf );
  1022. *ppf = NULL;
  1023. if (Temp <= SizeThreshold) {
  1024. return( DeleteSingleFile( DirName, FileName, TRUE ) );
  1025. }
  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.\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.\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. }
  1127. else {
  1128. if ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
  1129. return(TRUE);
  1130. }
  1131. psz = "file";
  1132. }
  1133. BuildError(
  1134. "CanonicalizePathName: %s --> %s is not a %s\n",
  1135. SourcePath,
  1136. PathBuffer,
  1137. psz);
  1138. return(FALSE);
  1139. }
  1140. static char FormatPathBuffer[ DB_MAX_PATH_LENGTH ];
  1141. //+---------------------------------------------------------------------------
  1142. //
  1143. // Function: FormatPathName
  1144. //
  1145. // Synopsis: Take a directory name and relative pathname and merges the
  1146. // two into a correctly formatted path. If the resulting path
  1147. // has the current directory as a component, the current
  1148. // directory part is removed.
  1149. //
  1150. // Arguments: [DirName] -- Directory
  1151. // [FileName] -- Pathname relative to [DirName]
  1152. //
  1153. // Returns: Resulting string (should not be freed).
  1154. //
  1155. // Notes: Example: DirName="f:\nt\private\foo\subdir1\subdir2"
  1156. // FileName="..\..\bar.c"
  1157. // CurrentDirectory="f:\nt\private"
  1158. // Result="foo\bar.c"
  1159. //
  1160. //----------------------------------------------------------------------------
  1161. LPSTR
  1162. FormatPathName(
  1163. LPSTR DirName,
  1164. LPSTR FileName
  1165. )
  1166. {
  1167. UINT cb;
  1168. LPSTR p;
  1169. CopyString(FormatPathBuffer, CurrentDirectory, TRUE);
  1170. if (DirName && *DirName) {
  1171. if (DirName[1] == ':') {
  1172. p = FormatPathBuffer;
  1173. }
  1174. else
  1175. if (DirName[0] == '\\') {
  1176. p = FormatPathBuffer + 2;
  1177. }
  1178. else {
  1179. p = FormatPathBuffer + strlen(FormatPathBuffer);
  1180. *p++ = '\\';
  1181. }
  1182. CopyString(p, DirName, TRUE);
  1183. }
  1184. p = FormatPathBuffer + strlen(FormatPathBuffer);
  1185. if (p[-1] != '\\') {
  1186. *p++ = '\\';
  1187. *p = '\0';
  1188. }
  1189. if (FileName[1] == ':') {
  1190. p = FormatPathBuffer;
  1191. }
  1192. else
  1193. if (FileName[0] == '\\') {
  1194. p = FormatPathBuffer + 2;
  1195. }
  1196. else
  1197. if (!strncmp(FileName, ".\\", 2)) {
  1198. FileName += 2;
  1199. }
  1200. else
  1201. if (!strncmp(FileName, "..\\", 3)) {
  1202. do
  1203. {
  1204. p--;
  1205. while (*--p != '\\') {
  1206. if (p <= FormatPathBuffer) {
  1207. p = FormatPathBuffer;
  1208. break;
  1209. }
  1210. }
  1211. p++;
  1212. FileName += 3;
  1213. }
  1214. while (!strncmp(FileName, "..\\", 3) && (p != FormatPathBuffer));
  1215. }
  1216. CopyString(p, FileName, TRUE);
  1217. cb = strlen(CurrentDirectory);
  1218. p = FormatPathBuffer + cb;
  1219. if (!fAlwaysPrintFullPath) {
  1220. if (!_strnicmp(CurrentDirectory, FormatPathBuffer, cb) && *p == '\\') {
  1221. return(p + 1);
  1222. }
  1223. }
  1224. return(FormatPathBuffer);
  1225. }
  1226. //+---------------------------------------------------------------------------
  1227. //
  1228. // Function: AppendString
  1229. //
  1230. //----------------------------------------------------------------------------
  1231. LPSTR
  1232. AppendString(
  1233. LPSTR Destination,
  1234. LPSTR Source,
  1235. BOOL PrefixWithSpace
  1236. )
  1237. {
  1238. if (Source != NULL) {
  1239. while (*Destination) {
  1240. Destination++;
  1241. }
  1242. if (PrefixWithSpace) {
  1243. *Destination++ = ' ';
  1244. }
  1245. while (*Destination = *Source++) {
  1246. Destination++;
  1247. }
  1248. }
  1249. return(Destination);
  1250. }
  1251. #if DBG
  1252. //+---------------------------------------------------------------------------
  1253. //
  1254. // Function: AssertPathString
  1255. //
  1256. //----------------------------------------------------------------------------
  1257. VOID
  1258. AssertPathString(LPSTR pszPath)
  1259. {
  1260. LPSTR p = pszPath;
  1261. while (*p != '\0') {
  1262. if ((*p >= 'A' && *p <= 'Z') || *p == '/') {
  1263. BuildError("Bad Path string: '%s'\n", pszPath);
  1264. assert(FALSE);
  1265. }
  1266. p++;
  1267. }
  1268. }
  1269. #endif
  1270. //+---------------------------------------------------------------------------
  1271. //
  1272. // Function: CopyString
  1273. //
  1274. //----------------------------------------------------------------------------
  1275. LPSTR
  1276. CopyString(
  1277. LPSTR Destination,
  1278. LPSTR Source,
  1279. BOOL fPath)
  1280. {
  1281. UCHAR ch;
  1282. LPSTR Result;
  1283. Result = Destination;
  1284. while ((ch = *Source++) != '\0') {
  1285. if (fPath) {
  1286. if (ch >= 'A' && ch <= 'Z') {
  1287. ch -= (UCHAR) ('A' - 'a');
  1288. } else if (ch == '/') {
  1289. ch = '\\';
  1290. }
  1291. }
  1292. *Destination++ = ch;
  1293. }
  1294. *Destination = ch;
  1295. return(Result);
  1296. }
  1297. //+---------------------------------------------------------------------------
  1298. //
  1299. // Function: MakeString
  1300. //
  1301. //----------------------------------------------------------------------------
  1302. VOID
  1303. MakeString(
  1304. LPSTR *Destination,
  1305. LPSTR Source,
  1306. BOOL fPath,
  1307. MemType mt
  1308. )
  1309. {
  1310. if (Source == NULL) {
  1311. Source = "";
  1312. }
  1313. AllocMem(strlen(Source) + 1, Destination, mt);
  1314. *Destination = CopyString(*Destination, Source, fPath);
  1315. }
  1316. //+---------------------------------------------------------------------------
  1317. //
  1318. // Function: MakeExpandedString
  1319. //
  1320. //----------------------------------------------------------------------------
  1321. VOID
  1322. MakeExpandedString(
  1323. LPSTR *Destination,
  1324. LPSTR Source
  1325. )
  1326. {
  1327. AllocMem(strlen(Source) + strlen(NtRoot) + 1, Destination, MT_DIRSTRING);
  1328. sprintf(*Destination, "%s%s", NtRoot, Source);
  1329. }
  1330. //+---------------------------------------------------------------------------
  1331. //
  1332. // Function: FreeString
  1333. //
  1334. //----------------------------------------------------------------------------
  1335. VOID
  1336. FreeString(LPSTR *ppsz, MemType mt)
  1337. {
  1338. if (*ppsz != NULL) {
  1339. FreeMem(ppsz, mt);
  1340. }
  1341. }
  1342. //+---------------------------------------------------------------------------
  1343. //
  1344. // Function: FormatNumber
  1345. //
  1346. //----------------------------------------------------------------------------
  1347. LPSTR
  1348. FormatNumber(
  1349. ULONG Number
  1350. )
  1351. {
  1352. USHORT i;
  1353. LPSTR p;
  1354. static char FormatNumberBuffer[16];
  1355. p = FormatNumberBuffer + sizeof( FormatNumberBuffer ) - 1;
  1356. *p = '\0';
  1357. i = 0;
  1358. do {
  1359. if (i != 0 && (i % 3) == 0) {
  1360. *--p = ',';
  1361. }
  1362. i++;
  1363. *--p = (UCHAR) ((Number % 10) + '0');
  1364. Number /= 10;
  1365. } while (Number != 0);
  1366. return( p );
  1367. }
  1368. //+---------------------------------------------------------------------------
  1369. //
  1370. // Function: FormatTime
  1371. //
  1372. //----------------------------------------------------------------------------
  1373. LPSTR
  1374. FormatTime(
  1375. ULONG Seconds
  1376. )
  1377. {
  1378. ULONG Hours, Minutes;
  1379. static char FormatTimeBuffer[16];
  1380. Hours = Seconds / 3600;
  1381. Seconds = Seconds % 3600;
  1382. Minutes = Seconds / 60;
  1383. Seconds = Seconds % 60;
  1384. sprintf( FormatTimeBuffer,
  1385. "%2ld:%02ld:%02ld",
  1386. Hours,
  1387. Minutes,
  1388. Seconds
  1389. );
  1390. return( FormatTimeBuffer );
  1391. }
  1392. //+---------------------------------------------------------------------------
  1393. //
  1394. // Function: AToX
  1395. //
  1396. // Synopsis: Hex atoi with pointer bumping and success flag
  1397. //
  1398. // Arguments: [pp] -- String to convert
  1399. // [pul] -- [out] Result
  1400. //
  1401. // Returns: TRUE if success
  1402. //
  1403. //----------------------------------------------------------------------------
  1404. BOOL
  1405. AToX(LPSTR *pp, ULONG *pul)
  1406. {
  1407. LPSTR p = *pp;
  1408. int digit;
  1409. ULONG r;
  1410. BOOL fRet = FALSE;
  1411. while (*p == ' ') {
  1412. p++;
  1413. }
  1414. for (r = 0; isxdigit(digit = *p); p++) {
  1415. fRet = TRUE;
  1416. if (isdigit(digit)) {
  1417. digit -= '0';
  1418. } else if (isupper(digit)) {
  1419. digit -= 'A' - 10;
  1420. } else {
  1421. digit -= 'a' - 10;
  1422. }
  1423. r = (r << 4) + digit;
  1424. }
  1425. *pp = p;
  1426. *pul = r;
  1427. return(fRet);
  1428. }
  1429. //+---------------------------------------------------------------------------
  1430. //
  1431. // Function: AToD
  1432. //
  1433. // Synopsis: Decimal atoi with pointer bumping and success flag
  1434. //
  1435. // Arguments: [pp] -- String to convert
  1436. // [pul] -- [out] Result
  1437. //
  1438. // Returns: TRUE if success
  1439. //
  1440. //----------------------------------------------------------------------------
  1441. BOOL
  1442. AToD(LPSTR *pp, ULONG *pul)
  1443. {
  1444. LPSTR p = *pp;
  1445. int digit;
  1446. ULONG r;
  1447. BOOL fRet = FALSE;
  1448. while (*p == ' ') {
  1449. p++;
  1450. }
  1451. for (r = 0; isdigit(digit = *p); p++) {
  1452. fRet = TRUE;
  1453. r = (r * 10) + digit - '0';
  1454. }
  1455. *pp = p;
  1456. *pul = r;
  1457. return(fRet);
  1458. }
  1459. //+---------------------------------------------------------------------------
  1460. //
  1461. // Logging and Display Functions
  1462. //
  1463. //----------------------------------------------------------------------------
  1464. VOID
  1465. __cdecl
  1466. LogMsg(const char *pszfmt, ...)
  1467. {
  1468. va_list va;
  1469. if (LogFile != NULL) {
  1470. va_start(va, pszfmt);
  1471. vfprintf(LogFile, pszfmt, va);
  1472. va_end(va);
  1473. }
  1474. }
  1475. VOID
  1476. EnterMessageMode(VOID)
  1477. {
  1478. EnterCriticalSection(&TTYCriticalSection);
  1479. if (fConsoleInitialized &&
  1480. (NewConsoleMode & ENABLE_WRAP_AT_EOL_OUTPUT) == 0) {
  1481. SetConsoleMode(
  1482. GetStdHandle(STD_ERROR_HANDLE),
  1483. NewConsoleMode | ENABLE_WRAP_AT_EOL_OUTPUT);
  1484. }
  1485. }
  1486. VOID
  1487. LeaveMessageMode(VOID)
  1488. {
  1489. if (fConsoleInitialized &&
  1490. (NewConsoleMode & ENABLE_WRAP_AT_EOL_OUTPUT) == 0) {
  1491. SetConsoleMode(GetStdHandle(STD_ERROR_HANDLE), NewConsoleMode);
  1492. }
  1493. LeaveCriticalSection(&TTYCriticalSection);
  1494. }
  1495. VOID
  1496. __cdecl
  1497. BuildMsg(const char *pszfmt, ...)
  1498. {
  1499. va_list va;
  1500. EnterMessageMode();
  1501. ClearLine();
  1502. va_start(va, pszfmt);
  1503. fprintf(stderr, "BUILD: ");
  1504. vfprintf(stderr, pszfmt, va);
  1505. va_end(va);
  1506. fflush(stderr);
  1507. LeaveMessageMode();
  1508. }
  1509. VOID
  1510. __cdecl
  1511. BuildMsgRaw(const char *pszfmt, ...)
  1512. {
  1513. va_list va;
  1514. EnterMessageMode();
  1515. va_start(va, pszfmt);
  1516. vfprintf(stderr, pszfmt, va);
  1517. va_end(va);
  1518. fflush(stderr);
  1519. LeaveMessageMode();
  1520. }
  1521. VOID
  1522. __cdecl
  1523. BuildError(const char *pszfmt, ...)
  1524. {
  1525. va_list va;
  1526. EnterMessageMode();
  1527. ClearLine();
  1528. va_start(va, pszfmt);
  1529. fprintf(stderr, "BUILD: ");
  1530. if (Frb.fOpen) {
  1531. fprintf (stderr, "%s(%hu): ", Frb.pszFile, Frb.cLine);
  1532. }
  1533. vfprintf(stderr, pszfmt, va);
  1534. va_end(va);
  1535. fflush(stderr);
  1536. LeaveMessageMode();
  1537. if (LogFile != NULL) {
  1538. va_start(va, pszfmt);
  1539. fprintf(LogFile, "BUILD: ");
  1540. if (Frb.fOpen) {
  1541. fprintf (LogFile, "%s(%hu): ", Frb.pszFile, Frb.cLine);
  1542. }
  1543. vfprintf(LogFile, pszfmt, va);
  1544. va_end(va);
  1545. fflush(LogFile);
  1546. }
  1547. }
  1548. VOID
  1549. __cdecl
  1550. BuildErrorRaw(const char *pszfmt, ...)
  1551. {
  1552. va_list va;
  1553. EnterMessageMode();
  1554. va_start(va, pszfmt);
  1555. vfprintf(stderr, pszfmt, va);
  1556. va_end(va);
  1557. fflush(stderr);
  1558. LeaveMessageMode();
  1559. if (LogFile != NULL) {
  1560. va_start(va, pszfmt);
  1561. vfprintf(LogFile, pszfmt, va);
  1562. va_end(va);
  1563. fflush(LogFile);
  1564. }
  1565. }