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.

4372 lines
140 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1994
  5. //
  6. // File: buildexe.c
  7. //
  8. // Contents: Functions related to spawning processes and processing
  9. // their output, using pipes and multiple threads.
  10. //
  11. // History: 22-May-89 SteveWo Created
  12. // ... see SLM logs
  13. // 26-Jul-94 LyleC Cleanup/Add Pass0 Support
  14. //
  15. //----------------------------------------------------------------------------
  16. #include "build.h"
  17. #include <fcntl.h>
  18. //+---------------------------------------------------------------------------
  19. //
  20. // Global Data
  21. //
  22. //----------------------------------------------------------------------------
  23. #define DEFAULT_LPS (fStatusTree? 5000 : 50)
  24. #define LastRow(pts) ((USHORT) ((pts)->cRowTotal - 1))
  25. #define LastCol(pts) ((USHORT) ((pts)->cColTotal - 1))
  26. typedef struct _PARALLEL_CHILD {
  27. PTHREADSTATE ThreadState;
  28. HANDLE Event;
  29. CHAR ExecuteProgramCmdLine[1024];
  30. } PARALLEL_CHILD, *PPARALLEL_CHILD;
  31. ULONG_PTR StartCompileTime;
  32. DWORD OldConsoleMode;
  33. DWORD NewConsoleMode;
  34. HANDLE *WorkerThreads;
  35. HANDLE *WorkerEvents;
  36. ULONG NumberProcesses;
  37. ULONG ThreadsStarted;
  38. BOOLEAN fConsoleInitialized = FALSE;
  39. BYTE ScreenCell[2];
  40. BYTE StatusCell[2];
  41. #define STATE_UNKNOWN 0
  42. #define STATE_COMPILING 1
  43. #define STATE_ASSEMBLING 2
  44. #define STATE_LIBING 3
  45. #define STATE_LINKING 4
  46. #define STATE_C_PREPROC 5
  47. #define STATE_S_PREPROC 6
  48. #define STATE_PRECOMP 7
  49. #define STATE_MKTYPLIB 8
  50. #define STATE_MIDL 9
  51. #define STATE_MC 10
  52. #define STATE_STATUS 11
  53. #define STATE_BINPLACE 12
  54. #define STATE_VSTOOL 13
  55. #define STATE_ASN 14
  56. #define STATE_PACKING 15
  57. #define STATE_BATCHCOMPILE 16
  58. #define STATE_BSCMAKING 17
  59. #define STATE_CTCOMPILING 18
  60. #define STATE_AUTODOCING 19
  61. #define STATE_DOCCHECKING 20
  62. #define STATE_POSTBUILD 21
  63. #define FLAGS_CXX_FILE 0x0001
  64. #define FLAGS_WARNINGS_ARE_ERRORS 0x0002
  65. LPSTR States[] = {
  66. "Unknown", // 0
  67. "Compiling", // 1
  68. "Assembling", // 2
  69. "Building Library", // 3
  70. "Linking Executable", // 4
  71. "Preprocessing", // 5
  72. "Assembling", // 6
  73. "Precompiling", // 7
  74. "Building Type Library", // 8
  75. "Running MIDL on", // 9
  76. "Compiling message file", // 10
  77. "Build Status Line", // 11
  78. "Binplacing", // 12
  79. "Processing", // 13
  80. "Running ASN Compiler on", // 14
  81. "Packing Theme", // 15
  82. "Compiling", // 16
  83. "Building Browse File", // 17
  84. "CTC Compiling", // 18
  85. "Generating Documentation", // 19
  86. "Checking Doc Comments", // 20
  87. "PostBuild" //21
  88. };
  89. //----------------------------------------------------------------------------
  90. //
  91. // Function prototypes
  92. //
  93. //----------------------------------------------------------------------------
  94. VOID
  95. GetScreenSize(THREADSTATE *ThreadState);
  96. VOID
  97. GetCursorPosition(USHORT *pRow, USHORT *pCol, USHORT *pRowTop);
  98. VOID
  99. SetCursorPosition(USHORT Row, USHORT Col);
  100. VOID
  101. WriteConsoleCells(
  102. LPSTR String,
  103. USHORT StringLength,
  104. USHORT Row,
  105. USHORT Col,
  106. BYTE *Attribute);
  107. VOID
  108. MoveRectangleUp (
  109. USHORT Top,
  110. USHORT Left,
  111. USHORT Bottom,
  112. USHORT Right,
  113. USHORT NumRow,
  114. BYTE *FillCell);
  115. VOID
  116. ReadConsoleCells(
  117. BYTE *pScreenCell,
  118. USHORT cb,
  119. USHORT Row,
  120. USHORT Column);
  121. VOID
  122. ClearRows(
  123. PTHREADSTATE ThreadState,
  124. USHORT Top,
  125. USHORT NumRows,
  126. PBYTE Cell
  127. );
  128. LPSTR
  129. IsolateFirstToken(
  130. LPSTR *pp,
  131. CHAR delim
  132. );
  133. LPSTR
  134. IsolateLastToken(
  135. LPSTR p,
  136. CHAR delim
  137. );
  138. DWORD
  139. ParallelChildStart(
  140. PPARALLEL_CHILD Data
  141. );
  142. DWORD
  143. PipeSpawnClose (
  144. FILE *pstream
  145. );
  146. FILE *
  147. PipeSpawn (
  148. const CHAR *cmdstring
  149. );
  150. BOOL
  151. DetermineChildState(
  152. PTHREADSTATE ThreadState,
  153. LPSTR p
  154. );
  155. void
  156. PrintChildState(
  157. PTHREADSTATE ThreadState,
  158. LPSTR p,
  159. PFILEREC FileDB
  160. );
  161. BOOL
  162. CoffFilter(
  163. PTHREADSTATE ThreadState,
  164. LPSTR p
  165. );
  166. //+---------------------------------------------------------------------------
  167. //
  168. // Function: RestoreConsoleMode
  169. //
  170. //----------------------------------------------------------------------------
  171. VOID
  172. RestoreConsoleMode(VOID)
  173. {
  174. SetConsoleMode(GetStdHandle(STD_ERROR_HANDLE), OldConsoleMode);
  175. NewConsoleMode = OldConsoleMode;
  176. }
  177. //+---------------------------------------------------------------------------
  178. //
  179. // Function: IsolateFirstToken
  180. //
  181. // Synopsis: Returns the first token in a string.
  182. //
  183. // Arguments: [pp] -- String to parse
  184. // [delim] -- Token delimiter
  185. //
  186. // Returns: Pointer to first token
  187. //
  188. // Notes: Leading spaces are ignored.
  189. //
  190. //----------------------------------------------------------------------------
  191. LPSTR
  192. IsolateFirstToken(
  193. LPSTR *pp,
  194. CHAR delim
  195. )
  196. {
  197. LPSTR p, Result;
  198. p = *pp;
  199. while (*p <= ' ') {
  200. if (!*p) {
  201. *pp = p;
  202. return ( "" );
  203. } else
  204. p++;
  205. }
  206. Result = p;
  207. while (*p) {
  208. if (*p == delim) {
  209. *p++ = '\0';
  210. break;
  211. } else {
  212. p++;
  213. }
  214. }
  215. *pp = p;
  216. if (*Result == '\0') // don't overrun the buffer
  217. return ( Result );
  218. if (*Result == '.' && Result[1] == '\\') {
  219. return ( Result+2 );
  220. } else {
  221. return ( Result );
  222. }
  223. }
  224. //+---------------------------------------------------------------------------
  225. //
  226. // Function: IsolateLastToken
  227. //
  228. // Synopsis: Return the last token in a string.
  229. //
  230. // Arguments: [p] -- String to parse
  231. // [delim] -- Token delimiter
  232. //
  233. // Returns: Pointer to last token
  234. //
  235. // Notes: Trailing spaces are skipped.
  236. //
  237. //----------------------------------------------------------------------------
  238. LPSTR
  239. IsolateLastToken(
  240. LPSTR p,
  241. CHAR delim
  242. )
  243. {
  244. LPSTR Start;
  245. Start = p;
  246. while (*p) {
  247. p++;
  248. }
  249. while (--p > Start) {
  250. if (*p <= ' ' || *p == ':') {
  251. *p = '\0';
  252. } else
  253. break;
  254. }
  255. while (p > Start) {
  256. if (*--p == delim) {
  257. p++;
  258. break;
  259. }
  260. }
  261. if (*p == '.' && p[1] == '\\') {
  262. return ( p+2 );
  263. } else {
  264. return ( p );
  265. }
  266. }
  267. //+---------------------------------------------------------------------------
  268. //
  269. // Function: TestPrefix
  270. //
  271. // Synopsis: Returns TRUE if [Prefix] is the first part of [pp]
  272. //
  273. //----------------------------------------------------------------------------
  274. BOOL
  275. TestPrefix(
  276. LPSTR *pp,
  277. LPSTR Prefix
  278. )
  279. {
  280. LPSTR p = *pp;
  281. UINT cb;
  282. if (!_strnicmp( p, Prefix, cb = strlen( Prefix ) )) {
  283. *pp = p + cb;
  284. return ( TRUE );
  285. } else {
  286. return ( FALSE );
  287. }
  288. }
  289. //+---------------------------------------------------------------------------
  290. //
  291. // Function: TestPrefixPath
  292. //
  293. // Synopsis: Returns TRUE if [Prefix] is the first part of [pp]
  294. // If the firstpart of [pp] (excluding whitespace) contains
  295. // backslashes, then only the right-most component is used
  296. //
  297. //----------------------------------------------------------------------------
  298. BOOL
  299. TestPrefixPath(
  300. LPSTR *pp,
  301. LPSTR Prefix
  302. )
  303. {
  304. LPSTR p = *pp;
  305. UINT cb;
  306. LPSTR PathString;
  307. INT PathStringLength ;
  308. LPSTR LastComp ;
  309. cb = strlen( Prefix );
  310. if (_strnicmp( p, Prefix, cb ) == 0 ) {
  311. *pp = p + cb;
  312. return ( TRUE );
  313. } else {
  314. PathString = strchr( p, ' ' );
  315. if ( PathString ) {
  316. PathStringLength = (INT) (PathString - p) ;
  317. *PathString = '\0';
  318. LastComp = strrchr( p, '\\' );
  319. *PathString = ' ';
  320. // Do we have backslashes (ie: a full path name to the tool name)?
  321. if ( LastComp ) {
  322. // Advance past the path.
  323. p = LastComp + 1;
  324. if ( _strnicmp( p, Prefix, cb ) == 0 ) {
  325. *pp = p + cb ;
  326. return ( TRUE );
  327. }
  328. }
  329. }
  330. return ( FALSE );
  331. }
  332. }
  333. //+---------------------------------------------------------------------------
  334. //
  335. // Function: Substr
  336. //
  337. //----------------------------------------------------------------------------
  338. BOOL
  339. Substr(
  340. LPSTR s,
  341. LPSTR p
  342. )
  343. {
  344. LPSTR x;
  345. while (*p) {
  346. x = s;
  347. while (*p++ == *x) {
  348. if (*x == '\0') {
  349. return ( TRUE );
  350. }
  351. x++;
  352. }
  353. if (*x == '\0') {
  354. return ( TRUE );
  355. }
  356. }
  357. return ( FALSE );
  358. }
  359. //+---------------------------------------------------------------------------
  360. //
  361. // Function: WriteTTY
  362. //
  363. // Synopsis: Writes the given string to the output device.
  364. //
  365. // Arguments: [ThreadState] -- Struct containing info about the output dev.
  366. // [p] -- String to display
  367. // [fStatusOutput] -- If TRUE then put on the status line.
  368. //
  369. //----------------------------------------------------------------------------
  370. VOID
  371. WriteTTY (THREADSTATE *ThreadState, LPSTR p, BOOL fStatusOutput)
  372. {
  373. USHORT SaveRow;
  374. USHORT SaveCol;
  375. USHORT SaveRowTop;
  376. USHORT cb, cbT;
  377. PBYTE Attribute;
  378. BOOL ForceNewline;
  379. if (fSuppressOutput)
  380. return;
  381. //
  382. // If we're not writing to the screen then don't do anything fancy, just
  383. // output the string.
  384. //
  385. if (!fStatus || !ThreadState->IsStdErrTty) {
  386. while (TRUE) {
  387. int cch;
  388. cch = strcspn(p, "\r");
  389. if (cch != 0) {
  390. fwrite(p, 1, cch, stderr);
  391. p += cch;
  392. }
  393. if (*p == '\0') {
  394. break;
  395. }
  396. if (p[1] != '\n') {
  397. fwrite(p, 1, 1, stderr);
  398. }
  399. p++;
  400. }
  401. fflush(stderr);
  402. return;
  403. }
  404. assert(ThreadState->cColTotal != 0);
  405. assert(ThreadState->cRowTotal != 0);
  406. //
  407. // Scroll as necessary
  408. //
  409. GetCursorPosition(&SaveRow, &SaveCol, &SaveRowTop);
  410. // During processing, there might be N threads that are displaying
  411. // messages and a single thread displaying directory-level
  412. // linking and building messages. We need to make sure there's room for
  413. // the single thread's message as well as ours. Since that single
  414. // thread displays one line at a time (including CRLF) we must make sure
  415. // that his display (as well as ours) doesn't inadvertantly scroll
  416. // the status line at the top. We do this by guaranteeing that there is
  417. // a blank line at the end.
  418. // We are synchronized with the single top-level thread
  419. // at a higher level than this routine via TTYCriticalSection. We
  420. // are, thus, assured that we control the cursor completely.
  421. // Stay off the LastRow
  422. if (SaveRow == LastRow(ThreadState)) {
  423. USHORT RowTop = 2;
  424. if (fStatus) {
  425. RowTop += SaveRowTop + (USHORT) NumberProcesses + 1;
  426. }
  427. MoveRectangleUp (
  428. RowTop, // Top
  429. 0, // Left
  430. LastRow(ThreadState), // Bottom
  431. LastCol(ThreadState), // Right
  432. 2, // NumRow
  433. ScreenCell); // FillCell
  434. SaveRow -= 2;
  435. SetCursorPosition(SaveRow, SaveCol);
  436. }
  437. //
  438. // Different color for the status line.
  439. //
  440. if (fStatusOutput) {
  441. Attribute = &StatusCell[1];
  442. } else {
  443. Attribute = &ScreenCell[1];
  444. }
  445. cb = (USHORT) strlen(p);
  446. //
  447. // Write out the string.
  448. //
  449. while (cb > 0) {
  450. ForceNewline = FALSE;
  451. if (cb > 1) {
  452. if (p[cb - 1] == '\n' && p[cb - 2] == '\r') {
  453. cb -= 2;
  454. ForceNewline = TRUE;
  455. }
  456. }
  457. if (cb >= ThreadState->cColTotal - SaveCol) {
  458. cbT = ThreadState->cColTotal - SaveCol;
  459. if (fFullErrors)
  460. ForceNewline = TRUE;
  461. } else {
  462. cbT = cb;
  463. }
  464. WriteConsoleCells(p, cbT, SaveRow, SaveCol, Attribute);
  465. SetCursorPosition(SaveRow, SaveCol);
  466. if (ForceNewline) {
  467. SaveCol = 0;
  468. SaveRow++;
  469. } else {
  470. SaveCol += cbT;
  471. }
  472. if (!fFullErrors) {
  473. break;
  474. }
  475. if (cb > cbT) {
  476. // we have more to go... do a newline
  477. // If we're back at the beginning of the bottom line
  478. if (SaveRow == LastRow(ThreadState)) {
  479. USHORT RowTop = 1;
  480. if (fStatus) {
  481. RowTop += SaveRowTop + (USHORT) NumberProcesses + 1;
  482. }
  483. // move window up one line (leaving two lines blank at bottom)
  484. MoveRectangleUp (
  485. RowTop, // Top
  486. 0, // Left
  487. LastRow(ThreadState), // Bottom
  488. LastCol(ThreadState), // Right
  489. 1, // NumRow
  490. ScreenCell); // FillCell
  491. SaveRow--;
  492. }
  493. SetCursorPosition(SaveRow, SaveCol);
  494. }
  495. cb -= cbT;
  496. p += cbT;
  497. }
  498. SetCursorPosition(SaveRow, SaveCol);
  499. }
  500. //+---------------------------------------------------------------------------
  501. //
  502. // Function: WriteTTYLoggingErrors
  503. //
  504. // Synopsis: Writes a message to the appropriate log file and also the
  505. // screen if specified.
  506. //
  507. // Arguments: [Warning] -- TRUE if the message is a warning
  508. // [ThreadState] -- Info about output device
  509. // [p] -- String
  510. //
  511. //----------------------------------------------------------------------------
  512. VOID
  513. WriteTTYLoggingErrors(
  514. BOOL Warning,
  515. PTHREADSTATE ThreadState,
  516. LPSTR p
  517. )
  518. {
  519. UINT cb;
  520. cb = strlen( p );
  521. // ignore empty strings
  522. if (0 == cb)
  523. return;
  524. if (fErrorLog) {
  525. fwrite( p, 1, cb, Warning ? WrnFile : ErrFile );
  526. }
  527. if (fShowWarningsOnScreen && Warning) {
  528. WriteTTY(ThreadState, p, FALSE);
  529. return;
  530. }
  531. if (!fErrorLog || !Warning) {
  532. WriteTTY(ThreadState, p, FALSE);
  533. }
  534. if (!Warning && fErrorBaseline && !bBaselineFailure) {
  535. // don't check for a new failure if there is already one
  536. if (NULL == pvBaselineContent || NULL == memfind(pvBaselineContent, cbBaselineContentSize, p, cb)) {
  537. // if there is no baseline file, or if the error is not found, we have new failure
  538. bBaselineFailure = TRUE;
  539. }
  540. }
  541. }
  542. //+---------------------------------------------------------------------------
  543. //
  544. // Function: RuntimeErrorFilter
  545. //
  546. // Synopsis: Filters output from the compiler so we know what's happening
  547. //
  548. // Arguments: [ThreadState] -- State of thread watching the compiler
  549. // (compiling, linking, etc...)
  550. // [p] -- Message we're trying to parse.
  551. // [FileName] -- [out] Filename in message
  552. // [LineNumber] -- [out] Line number in message
  553. // [Message] -- [out] Message number (for post processing)
  554. // [Warning] -- [out] TRUE if message is a warning.
  555. //
  556. // Returns: TRUE - Message is an error or warning
  557. // FALSE - Message is not an error or a warning
  558. //
  559. // History: 26-Jul-94 sbonev Created
  560. //
  561. // Notes:
  562. //
  563. // This routine filters strings that are not standard tool output.
  564. // Any unexpected error checking should go here
  565. //
  566. //----------------------------------------------------------------------------
  567. BOOL
  568. RuntimeErrorFilter(
  569. PTHREADSTATE ThreadState,
  570. LPSTR p,
  571. LPSTR *FileName,
  572. LPSTR *LineNumber,
  573. LPSTR *Message,
  574. BOOL *Warning
  575. )
  576. {
  577. if (strstr(p, "Exception occured:")) {
  578. *FileName = NULL;
  579. *LineNumber = NULL;
  580. *Message = p;
  581. *Warning = FALSE;
  582. return TRUE;
  583. }
  584. return FALSE;
  585. }
  586. //+---------------------------------------------------------------------------
  587. //
  588. // Function: MsCompilerFilter
  589. //
  590. // Synopsis: Filters output from the compiler so we know what's happening
  591. //
  592. // Arguments: [ThreadState] -- State of thread watching the compiler
  593. // (compiling, linking, etc...)
  594. // [p] -- Message we're trying to parse.
  595. // [FileName] -- [out] Filename in message
  596. // [LineNumber] -- [out] Line number in message
  597. // [Message] -- [out] Message number (for post processing)
  598. // [Warning] -- [out] TRUE if message is a warning.
  599. //
  600. // Returns: TRUE - Message is an error or warning
  601. // FALSE - Message is not an error or a warning
  602. //
  603. // History: 26-Jul-94 LyleC Created
  604. //
  605. // Notes:
  606. //
  607. // This routine filters strings in the MS compiler format. That is:
  608. //
  609. // {toolname} : {number}: {text}
  610. //
  611. // where:
  612. //
  613. // toolname If possible, the container and specific module that has
  614. // the error. For instance, the compiler uses
  615. // filename(linenum), the linker uses library(objname), etc.
  616. // If unable to provide a container, use the tool name.
  617. // number A number, prefixed with some tool identifier (C for
  618. // compiler, LNK for linker, LIB for librarian, N for nmake,
  619. // etc).
  620. // test The descriptive text of the message/error.
  621. //
  622. // Accepted String formats are:
  623. //
  624. // container(module): error/warning NUM ...
  625. // container(module) : error/warning NUM ...
  626. // container (module): error/warning NUM ...
  627. // container (module) : error/warning NUM ...
  628. //
  629. //----------------------------------------------------------------------------
  630. BOOL
  631. MsCompilerFilter(
  632. PTHREADSTATE ThreadState,
  633. LPSTR p,
  634. LPSTR *FileName,
  635. LPSTR *LineNumber,
  636. LPSTR *Message,
  637. BOOL *Warning
  638. )
  639. {
  640. LPSTR p1;
  641. BOOL fCommandLineWarning;
  642. *Message = NULL;
  643. p1 = p;
  644. if (strstr(p, "see declaration of"))
  645. goto notRecognized;
  646. if (strstr(p, "see previous definition of"))
  647. goto notRecognized;
  648. if (strstr(p, "while compiling class-template member function"))
  649. goto notRecognized;
  650. if (strstr(p, "see reference to function template instantiation"))
  651. goto notRecognized;
  652. if (strstr(p, "Compiler error (")) {
  653. *Message = p;
  654. *Warning = FALSE;
  655. if ((p1 = strstr( p, "source=" )))
  656. *LineNumber = p1+7;
  657. else
  658. *LineNumber = "1";
  659. *FileName = ThreadState->ChildCurrentFile;
  660. return TRUE;
  661. }
  662. if (!strncmp(p, "fatal error ", strlen("fatal error "))) {
  663. *Message = p;
  664. *Warning = FALSE;
  665. *LineNumber = "1";
  666. *FileName = ThreadState->ChildCurrentFile;
  667. return TRUE;
  668. } else if (!strncmp(p, "error ", strlen("error "))) {
  669. // Takes care of some C# error messages.
  670. *Message = p+strlen("error ");
  671. *Warning = FALSE;
  672. *LineNumber = "0";
  673. *FileName = ThreadState->ChildCurrentFile;
  674. return TRUE;
  675. }
  676. // First look for the " : " or "): " sequence.
  677. while (*p1) {
  678. if ((p1[0] == ')') && (p1[1] == ' ')) p1++;
  679. if ((p1[0] == ' ') || (p1[0] == ')')) {
  680. if (p1[1] == ':') {
  681. if (p1[2] == ' ') {
  682. *Message = p1 + 3;
  683. *p1 = '\0';
  684. break;
  685. } else
  686. break; // No sense going any further
  687. } else if ((p1[0] == ' ') && (p1[1] == '('))
  688. p1++;
  689. else
  690. break; // No sense going any further
  691. } else
  692. p1++;
  693. }
  694. if (*Message != NULL) {
  695. // then figure out if this is an error or warning.
  696. *Warning = TRUE; // Assume the best.
  697. fCommandLineWarning = FALSE;
  698. if (TestPrefix( Message, "error " ) ||
  699. TestPrefix( Message, "fatal error " ) ||
  700. TestPrefix( Message, "command line error " ) ||
  701. TestPrefix( Message, "Compiler error " )) {
  702. *Warning = FALSE;
  703. } else
  704. if (TestPrefix( Message, "warning " )) {
  705. *Warning = TRUE;
  706. } else
  707. if (TestPrefix( Message, "command line warning " )) {
  708. // Command-line warnings don't count when considering whether
  709. // warnings should be errors (under /WX).
  710. *Warning = TRUE;
  711. fCommandLineWarning = TRUE;
  712. } else
  713. if (TestPrefix( Message, "LNK6" )) {
  714. // Linker notes should be ignored.
  715. return (FALSE);
  716. }
  717. if (!fCommandLineWarning && (ThreadState->ChildFlags & FLAGS_WARNINGS_ARE_ERRORS) != 0) {
  718. if (Substr( "X0000", *Message )) {
  719. *Warning = TRUE; // Special case this one. Never an error
  720. } else {
  721. *Warning = FALSE; // Warnings treated as errors for this compile
  722. }
  723. }
  724. // Set the container name and look for the module paren's
  725. *FileName = p;
  726. *LineNumber = NULL;
  727. p1 = p;
  728. while (*p1) {
  729. if (*p1 == '(' && p1[1] != ')') {
  730. *p1 = '\0';
  731. p1++;
  732. *LineNumber = p1;
  733. while (*p1) {
  734. if (*p1 == ')') {
  735. *p1 = '\0';
  736. break;
  737. }
  738. p1++;
  739. }
  740. break;
  741. }
  742. p1++;
  743. }
  744. return (TRUE);
  745. }
  746. notRecognized:
  747. return RuntimeErrorFilter(ThreadState, p, FileName, LineNumber, Message, Warning);
  748. }
  749. //+---------------------------------------------------------------------------
  750. //
  751. // Function: FormatMsErrorMessage
  752. //
  753. // Synopsis: Take the information obtained from MsCompilerFilter,
  754. // reconstruct the error message, and print it to the screen.
  755. //
  756. //----------------------------------------------------------------------------
  757. VOID
  758. FormatMsErrorMessage(
  759. PTHREADSTATE ThreadState,
  760. LPSTR FileName,
  761. LPSTR LineNumber,
  762. LPSTR Message,
  763. BOOL Warning
  764. )
  765. {
  766. char *DirectoryToUse;
  767. SIZE_T BufferUsed, BufferLen;
  768. LPSTR pszBuffer;
  769. if (fColorConsole) {
  770. if (Warning)
  771. SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), COLOR_WARNING);
  772. else
  773. SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), COLOR_ERROR);
  774. }
  775. if (ThreadState->ChildState == STATE_LIBING) {
  776. if (Warning) {
  777. RunningTotals.NumberLibraryWarnings++;
  778. ThreadState->BuildMetrics.NumberLibraryWarnings++;
  779. } else {
  780. RunningTotals.NumberLibraryErrors++;
  781. ThreadState->BuildMetrics.NumberLibraryErrors++;
  782. }
  783. }
  784. else
  785. if ((ThreadState->ChildState == STATE_LINKING) ||
  786. (ThreadState->ChildState == STATE_BINPLACE)) {
  787. if (Warning) {
  788. RunningTotals.NumberLinkWarnings++;
  789. ThreadState->BuildMetrics.NumberLinkWarnings++;
  790. } else {
  791. RunningTotals.NumberLinkErrors++;
  792. ThreadState->BuildMetrics.NumberLinkErrors++;
  793. }
  794. } else {
  795. if (Warning) {
  796. RunningTotals.NumberCompileWarnings++;
  797. ThreadState->BuildMetrics.NumberCompileWarnings++;
  798. } else {
  799. RunningTotals.NumberCompileErrors++;
  800. ThreadState->BuildMetrics.NumberCompileErrors++;
  801. if (ThreadState->CompileDirDB) {
  802. ThreadState->CompileDirDB->DirFlags |= DIRDB_COMPILEERRORS;
  803. }
  804. }
  805. }
  806. // start filling up the buffer for the XML log file;
  807. // however, we are going to use the same buffer even if no XML log is requested
  808. // safe to use - it is protected by the TTY critical section
  809. ZeroMemory(szXMLBuffer, sizeof(szXMLBuffer));
  810. pszBuffer = szXMLBuffer;
  811. BufferUsed = 0;
  812. BufferLen = sizeof(szXMLBuffer) - 1;
  813. if (fParallel && !fNoThreadIndex ) {
  814. BufferUsed = _snprintf(pszBuffer, BufferLen, "%d>", ThreadState->ThreadIndex);
  815. pszBuffer += BufferUsed;
  816. BufferLen -= BufferUsed;
  817. }
  818. if (FileName) {
  819. DirectoryToUse = ThreadState->ChildCurrentDirectory;
  820. if (TestPrefix( &FileName, CurrentDirectory )) {
  821. DirectoryToUse = CurrentDirectory;
  822. if (*FileName == '\\') {
  823. FileName++;
  824. }
  825. }
  826. if (TestPrefix( &FileName, ThreadState->ChildCurrentDirectory )) {
  827. DirectoryToUse = ThreadState->ChildCurrentDirectory;
  828. if (*FileName == '\\') {
  829. FileName++;
  830. }
  831. }
  832. // check for some special cases when the FileName is actually the tool name
  833. // and should not be prepended with path
  834. if (ThreadState->FilterProc == CoffFilter && _stricmp(FileName, "link") == 0 ||
  835. ThreadState->FilterProc == CoffFilter && _stricmp(FileName, "lib") == 0) {
  836. BufferUsed = strlen(strncat(pszBuffer, FileName, BufferLen));
  837. } else {
  838. BufferUsed = strlen(strncat(pszBuffer, FormatPathName( DirectoryToUse, FileName), BufferLen));
  839. }
  840. pszBuffer += BufferUsed;
  841. BufferLen -= BufferUsed;
  842. }
  843. if (LineNumber && strlen(LineNumber) > 0) {
  844. BufferUsed = _snprintf(pszBuffer, BufferLen, "(%s)%s", LineNumber, FileName && strlen(FileName) ? " : " : "");
  845. pszBuffer += BufferUsed;
  846. BufferLen -= BufferUsed;
  847. }
  848. _snprintf(pszBuffer, BufferLen, "%s %s", Warning ? "warning" : "error", Message);
  849. if (Warning) {
  850. ThreadState->BuildMetrics.NumberActWarnings++;
  851. } else {
  852. ThreadState->BuildMetrics.NumberActErrors++;
  853. }
  854. WriteTTYLoggingErrors( Warning, ThreadState, szXMLBuffer);
  855. WriteTTYLoggingErrors( Warning, ThreadState, "\r\n" );
  856. if (fXMLOutput || fXMLFragment) {
  857. XMLThreadWrite(ThreadState, "<%s MESSAGE=\"%s\"/>", Warning ? "WARNING" : "ERROR", XMLEncodeBuiltInEntities(szXMLBuffer, sizeof(szXMLBuffer)));
  858. }
  859. if (fColorConsole)
  860. SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), DefaultConsoleAttributes);
  861. }
  862. //+---------------------------------------------------------------------------
  863. //
  864. // Function: PassThrough
  865. //
  866. // Synopsis: Keep track of and print the given message without any
  867. // filtering.
  868. //
  869. // Arguments: [ThreadState] --
  870. // [p] -- Message
  871. // [Warning] -- TRUE if warning
  872. //
  873. // Returns: FALSE
  874. //
  875. //----------------------------------------------------------------------------
  876. BOOL
  877. PassThrough(
  878. PTHREADSTATE ThreadState,
  879. LPSTR p,
  880. BOOL Warning
  881. )
  882. {
  883. if (fColorConsole) {
  884. if (Warning)
  885. SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), COLOR_WARNING);
  886. else
  887. SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), COLOR_ERROR);
  888. }
  889. if (ThreadState->ChildState == STATE_VSTOOL) {
  890. if (Warning) {
  891. RunningTotals.NumberVSToolWarnings++;
  892. ThreadState->BuildMetrics.NumberVSToolWarnings++;
  893. } else {
  894. RunningTotals.NumberVSToolErrors++;
  895. ThreadState->BuildMetrics.NumberVSToolErrors++;
  896. }
  897. } else
  898. if (ThreadState->ChildState == STATE_LIBING) {
  899. if (Warning) {
  900. RunningTotals.NumberLibraryWarnings++;
  901. ThreadState->BuildMetrics.NumberLibraryWarnings++;
  902. } else {
  903. RunningTotals.NumberLibraryErrors++;
  904. ThreadState->BuildMetrics.NumberLibraryErrors++;
  905. }
  906. } else
  907. if (ThreadState->ChildState == STATE_LINKING) {
  908. if (Warning) {
  909. RunningTotals.NumberLinkWarnings++;
  910. ThreadState->BuildMetrics.NumberLinkWarnings++;
  911. } else {
  912. RunningTotals.NumberLinkErrors++;
  913. ThreadState->BuildMetrics.NumberLinkErrors++;
  914. }
  915. } else
  916. if (ThreadState->ChildState == STATE_BINPLACE) {
  917. if (Warning) {
  918. RunningTotals.NumberBinplaceWarnings++;
  919. ThreadState->BuildMetrics.NumberBinplaceWarnings++;
  920. } else {
  921. RunningTotals.NumberBinplaceErrors++;
  922. ThreadState->BuildMetrics.NumberBinplaceErrors++;
  923. }
  924. } else {
  925. if (Warning) {
  926. RunningTotals.NumberCompileWarnings++;
  927. ThreadState->BuildMetrics.NumberCompileWarnings++;
  928. } else {
  929. RunningTotals.NumberCompileErrors++;
  930. ThreadState->BuildMetrics.NumberCompileErrors++;
  931. if (ThreadState->CompileDirDB) {
  932. ThreadState->CompileDirDB->DirFlags |= DIRDB_COMPILEERRORS;
  933. }
  934. }
  935. }
  936. // safe to use. it is protected by the TTY critical section
  937. ZeroMemory(szXMLBuffer, sizeof(szXMLBuffer));
  938. if (fParallel && !fNoThreadIndex) {
  939. _snprintf(szXMLBuffer, sizeof(szXMLBuffer)-1, "%d>%s", ThreadState->ThreadIndex, p);
  940. } else {
  941. strncpy(szXMLBuffer, p, sizeof(szXMLBuffer)-1);
  942. }
  943. if (Warning) {
  944. ThreadState->BuildMetrics.NumberActWarnings++;
  945. } else {
  946. ThreadState->BuildMetrics.NumberActErrors++;
  947. }
  948. WriteTTYLoggingErrors( Warning, ThreadState, szXMLBuffer );
  949. WriteTTYLoggingErrors( Warning, ThreadState, "\r\n" );
  950. if (fXMLOutput || fXMLFragment) {
  951. XMLThreadWrite(ThreadState, "<%s MESSAGE=\"%s\"/>", Warning ? "WARNING" : "ERROR", XMLEncodeBuiltInEntities(szXMLBuffer, sizeof(szXMLBuffer)));
  952. }
  953. if (fColorConsole)
  954. SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), DefaultConsoleAttributes);
  955. return ( FALSE );
  956. }
  957. //+---------------------------------------------------------------------------
  958. //
  959. // Function: PassThroughFilter
  960. //
  961. // Synopsis: Straight pass-through filter for compiler messages
  962. //
  963. //----------------------------------------------------------------------------
  964. BOOL
  965. PassThroughFilter(
  966. PTHREADSTATE ThreadState,
  967. LPSTR p
  968. )
  969. {
  970. return PassThrough( ThreadState, p, FALSE );
  971. }
  972. //+---------------------------------------------------------------------------
  973. //
  974. // Function: NMakeFilter
  975. //
  976. // Synopsis: Filters output from NMAKE so we know what's happening
  977. //
  978. // Arguments: [ThreadState] -- State of thread watching the build
  979. // [p] -- Message we're trying to parse.
  980. //
  981. // Returns: TRUE - Message is an error or warning
  982. // FALSE - Message is not an error or a warning
  983. //
  984. // History: 10-Jun-99 patbr Created
  985. //
  986. //----------------------------------------------------------------------------
  987. BOOL
  988. NMakeFilter(
  989. PTHREADSTATE ThreadState,
  990. LPSTR p
  991. )
  992. {
  993. LPSTR FileName;
  994. LPSTR LineNumber;
  995. LPSTR Message;
  996. BOOL Warning;
  997. if (MsCompilerFilter( ThreadState, p,
  998. &FileName,
  999. &LineNumber,
  1000. &Message,
  1001. &Warning)) {
  1002. FormatMsErrorMessage( ThreadState,
  1003. FileName, LineNumber, Message, Warning);
  1004. return ( TRUE );
  1005. } else {
  1006. return ( FALSE );
  1007. }
  1008. }
  1009. //+---------------------------------------------------------------------------
  1010. //
  1011. // Function: BisonFilter
  1012. //
  1013. // Synopsis: Filters output from the bison compiler so we know what's happening
  1014. //
  1015. // Arguments: [ThreadState] -- State of thread watching the compiler
  1016. // (compiling, linking, etc...)
  1017. // [p] -- Message we're trying to parse.
  1018. //
  1019. // Returns: TRUE - Message is an error or warning
  1020. // FALSE - Message is not an error or a warning
  1021. //
  1022. // History: 04-Oct-99 TomSe Created
  1023. //
  1024. // Notes:
  1025. //
  1026. // This routine filters strings in the bison compiler format. That is:
  1027. //
  1028. // Accepted String formats are:
  1029. //
  1030. // ("myfile.y", line 3) error: unknown character: #
  1031. // "myfile.y", line 83: no input grammar
  1032. // vapi.y contains 1 useless nonterminal and 1 useless rule
  1033. //
  1034. //----------------------------------------------------------------------------
  1035. BOOL
  1036. BisonFilter(
  1037. PTHREADSTATE ThreadState,
  1038. LPSTR p
  1039. )
  1040. {
  1041. LPSTR FileName = NULL;
  1042. LPSTR LineNumber = NULL;
  1043. LPSTR Message = NULL;
  1044. BOOL Warning = TRUE;
  1045. // First colon marks beginnning of message.
  1046. LPSTR p1 = strchr(p,':');
  1047. if (p1) {
  1048. Message = p1 + 1;
  1049. *p1 = '\0';
  1050. // Get filename, line number.
  1051. p1 = p;
  1052. do {
  1053. Warning = FALSE;
  1054. // Skip (.
  1055. if ( '(' == *p1 ) {
  1056. p1++;
  1057. }
  1058. // Skip over leading quote in filename.
  1059. if ( '"' != *p1 ) {
  1060. // Unexpected format.
  1061. break;
  1062. }
  1063. p1++;
  1064. FileName = p1;
  1065. // Look for trailing quote in filename.
  1066. p1 = strchr( p1, '"');
  1067. if (NULL==p1) {
  1068. // Unexpected format.
  1069. FileName = NULL;
  1070. break;
  1071. }
  1072. *p1 = '\0';
  1073. p1++;
  1074. if (0 !=strncmp( p1, ", line ", 7)) {
  1075. // Unexpected format.
  1076. FileName = NULL;
  1077. break;
  1078. }
  1079. p1 += 7;
  1080. LineNumber = p1;
  1081. while (isdigit(*p1)) {
  1082. p1++;
  1083. }
  1084. *p1 = '\0';
  1085. }
  1086. while (0);
  1087. } else {
  1088. // Take whole string as message if no colon is found.
  1089. Message = p;
  1090. }
  1091. if (NULL==FileName) {
  1092. FileName = ThreadState->ChildCurrentFile;
  1093. }
  1094. FormatMsErrorMessage( ThreadState,
  1095. FileName, LineNumber, Message, Warning );
  1096. // This was a warning or error.
  1097. return TRUE ;
  1098. }
  1099. //+---------------------------------------------------------------------------
  1100. //
  1101. // Function: C510Filter
  1102. //
  1103. // Synopsis: Compiler filter which strips out unwanted warnings.
  1104. //
  1105. // Arguments: [ThreadState] --
  1106. // [p] --
  1107. //
  1108. //----------------------------------------------------------------------------
  1109. BOOL
  1110. C510Filter(
  1111. PTHREADSTATE ThreadState,
  1112. LPSTR p
  1113. )
  1114. {
  1115. LPSTR FileName;
  1116. LPSTR LineNumber;
  1117. LPSTR Message;
  1118. BOOL Warning;
  1119. LPSTR t;
  1120. PFILEREC FileDB;
  1121. if (MsCompilerFilter( ThreadState, p,
  1122. &FileName,
  1123. &LineNumber,
  1124. &Message,
  1125. &Warning
  1126. )
  1127. ) {
  1128. FormatMsErrorMessage( ThreadState,
  1129. FileName, LineNumber, Message, Warning );
  1130. return ( TRUE );
  1131. } else {
  1132. // If we're compiling, then the compiler spits out various bit of info,
  1133. // namely:
  1134. // 1. filename alone on a line (.c, .cpp, .cxx)
  1135. // 2. "Generating Code..." when the back-end is invoked
  1136. // 3. "Compiling..." when the front-end is invoked again
  1137. if (ThreadState->ChildState == STATE_COMPILING) {
  1138. if (0 == strcmp(p, "Generating Code...")) {
  1139. strcpy( ThreadState->ChildCurrentFile, "Generating Code..." );
  1140. PrintChildState(ThreadState, p, NULL);
  1141. return FALSE;
  1142. }
  1143. t = strrchr(p, '.');
  1144. if (t != NULL &&
  1145. (0 == strcmp(t, ".cxx") ||
  1146. 0 == strcmp(t, ".cpp") ||
  1147. 0 == strcmp(t, ".c"))) {
  1148. strcpy( ThreadState->ChildCurrentFile, IsolateLastToken(p, ' '));
  1149. // strcpy(ThreadState->ChildCurrentFile, p);
  1150. if (strstr(ThreadState->ChildCurrentFile, ".cxx") ||
  1151. strstr(ThreadState->ChildCurrentFile, ".cpp")) {
  1152. ThreadState->ChildFlags |= FLAGS_CXX_FILE;
  1153. } else {
  1154. ThreadState->ChildFlags &= ~FLAGS_CXX_FILE;
  1155. }
  1156. FileDB = NULL;
  1157. if (ThreadState->CompileDirDB) {
  1158. RunningTotals.NumberCompiles++;
  1159. ThreadState->BuildMetrics.NumberCompileWarnings++;
  1160. CopyString( // fixup path string
  1161. ThreadState->ChildCurrentFile,
  1162. ThreadState->ChildCurrentFile,
  1163. TRUE);
  1164. if (!fQuicky) {
  1165. FileDB = FindSourceFileDB(
  1166. ThreadState->CompileDirDB,
  1167. ThreadState->ChildCurrentFile,
  1168. NULL);
  1169. }
  1170. }
  1171. PrintChildState(ThreadState, p, FileDB);
  1172. return FALSE;
  1173. }
  1174. }
  1175. return ( FALSE );
  1176. }
  1177. }
  1178. //+---------------------------------------------------------------------------
  1179. //
  1180. // Function: MSBCFilter
  1181. //
  1182. // Synopsis: Filters output from the Basic compiler so we know what's happening
  1183. //
  1184. // Arguments: [ThreadState] -- State of thread watching the compiler
  1185. // [p] -- Message we're trying to parse.
  1186. //
  1187. // Returns: TRUE - Message is an error or warning
  1188. // FALSE - Message is not an error or a warning
  1189. //
  1190. // History: 08-Dec-09 marioch Created
  1191. //
  1192. //----------------------------------------------------------------------------
  1193. BOOL
  1194. MSBCFilter(
  1195. PTHREADSTATE ThreadState,
  1196. LPSTR p
  1197. )
  1198. {
  1199. LPSTR FileName;
  1200. LPSTR LineNumber;
  1201. LPSTR Message;
  1202. BOOL Warning;
  1203. if (!strncmp(p, "BC Compiler error", 17)) {
  1204. FormatMsErrorMessage( ThreadState,
  1205. ThreadState->ChildCurrentFile, NULL, p, FALSE );
  1206. return TRUE;
  1207. }
  1208. if (MsCompilerFilter( ThreadState, p,
  1209. &FileName,
  1210. &LineNumber,
  1211. &Message,
  1212. &Warning)) {
  1213. FormatMsErrorMessage( ThreadState,
  1214. FileName, LineNumber, Message, Warning );
  1215. return ( TRUE );
  1216. } else {
  1217. char *pErrorMsg;
  1218. if (NULL != (pErrorMsg = strstr(p, "error BC"))) {
  1219. FormatMsErrorMessage( ThreadState,
  1220. ThreadState->ChildCurrentFile, NULL, pErrorMsg+6, FALSE );
  1221. return TRUE;
  1222. }
  1223. return ( FALSE );
  1224. }
  1225. }
  1226. //+---------------------------------------------------------------------------
  1227. //
  1228. // Function: MSJVCFilter
  1229. //
  1230. // Synopsis: Filters output from the JVC compiler so we know what's happening
  1231. //
  1232. // Arguments: [ThreadState] -- State of thread watching the compiler
  1233. // [p] -- Message we're trying to parse.
  1234. //
  1235. // Returns: TRUE - Message is an error or warning
  1236. // FALSE - Message is not an error or a warning
  1237. //
  1238. // History: 24-Mar-99 patbr Created
  1239. //
  1240. //----------------------------------------------------------------------------
  1241. BOOL
  1242. MSJVCFilter(
  1243. PTHREADSTATE ThreadState,
  1244. LPSTR p
  1245. )
  1246. {
  1247. LPSTR FileName;
  1248. LPSTR LineNumber;
  1249. LPSTR Message;
  1250. BOOL Warning;
  1251. if (!strncmp(p, "fatal error J", 13) || !strncmp(p, "error J", 7)) {
  1252. if (fColorConsole)
  1253. SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), COLOR_ERROR);
  1254. WriteTTYLoggingErrors( FALSE, ThreadState, p );
  1255. WriteTTYLoggingErrors( FALSE, ThreadState, "\r\n" );
  1256. if (fColorConsole)
  1257. SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), DefaultConsoleAttributes);
  1258. RunningTotals.NumberCompileErrors++;
  1259. ThreadState->BuildMetrics.NumberCompileErrors++;
  1260. return TRUE;
  1261. }
  1262. if (MsCompilerFilter( ThreadState, p,
  1263. &FileName,
  1264. &LineNumber,
  1265. &Message,
  1266. &Warning)) {
  1267. FormatMsErrorMessage( ThreadState,
  1268. FileName, LineNumber, Message, Warning );
  1269. return ( TRUE );
  1270. } else {
  1271. return ( FALSE );
  1272. }
  1273. }
  1274. //+---------------------------------------------------------------------------
  1275. //
  1276. // Function: MSCoolFilter
  1277. //
  1278. // Synopsis: Filters output from the COOL compiler so we know what's happening
  1279. //
  1280. // Arguments: [ThreadState] -- State of thread watching the compiler
  1281. // [p] -- Message we're trying to parse.
  1282. //
  1283. // Returns: TRUE - Message is an error or warning
  1284. // FALSE - Message is not an error or a warning
  1285. //
  1286. // History: 2-Jun-99 patbr Created
  1287. //
  1288. //----------------------------------------------------------------------------
  1289. BOOL
  1290. MSCoolFilter(
  1291. PTHREADSTATE ThreadState,
  1292. LPSTR p
  1293. )
  1294. {
  1295. LPSTR FileName;
  1296. LPSTR LineNumber;
  1297. LPSTR Message;
  1298. BOOL Warning;
  1299. if (!strncmp(p, "fatal error SC", 14) || !strncmp(p, "error SC", 8)) {
  1300. if (fColorConsole)
  1301. SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), COLOR_ERROR);
  1302. WriteTTYLoggingErrors( FALSE, ThreadState, p );
  1303. WriteTTYLoggingErrors( FALSE, ThreadState, "\r\n" );
  1304. if (fColorConsole)
  1305. SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), DefaultConsoleAttributes);
  1306. RunningTotals.NumberCompileErrors++;
  1307. ThreadState->BuildMetrics.NumberCompileErrors++;
  1308. return TRUE;
  1309. }
  1310. if (MsCompilerFilter( ThreadState, p,
  1311. &FileName,
  1312. &LineNumber,
  1313. &Message,
  1314. &Warning)) {
  1315. FormatMsErrorMessage( ThreadState,
  1316. FileName, LineNumber, Message, Warning );
  1317. return ( TRUE );
  1318. } else {
  1319. return ( FALSE );
  1320. }
  1321. }
  1322. //+---------------------------------------------------------------------------
  1323. //
  1324. // Function: MSCSharpFilter
  1325. //
  1326. // Synopsis: Filters output from the CSharp compiler so we know what's happening
  1327. //
  1328. // Arguments: [ThreadState] -- State of thread watching the compiler
  1329. // [p] -- Message we're trying to parse.
  1330. //
  1331. // Returns: TRUE - Message is an error or warning
  1332. // FALSE - Message is not an error or a warning
  1333. //
  1334. // History: 6-Nov-00 sbonev Copy of MSCoolFilter
  1335. //
  1336. //----------------------------------------------------------------------------
  1337. BOOL
  1338. MSCSharpFilter(
  1339. PTHREADSTATE ThreadState,
  1340. LPSTR p
  1341. )
  1342. {
  1343. LPSTR FileName;
  1344. LPSTR LineNumber;
  1345. LPSTR Message;
  1346. BOOL Warning;
  1347. if (!strncmp(p, "fatal error CS", 14) || !strncmp(p, "error CS", 8)) {
  1348. Message = p + strlen("error ");
  1349. FileName = ".";
  1350. LineNumber = NULL;
  1351. Warning = FALSE;
  1352. FormatMsErrorMessage( ThreadState, FileName, LineNumber, Message, Warning );
  1353. RunningTotals.NumberCompileErrors++;
  1354. ThreadState->BuildMetrics.NumberCompileErrors++;
  1355. return TRUE;
  1356. }
  1357. if (MsCompilerFilter( ThreadState, p,
  1358. &FileName,
  1359. &LineNumber,
  1360. &Message,
  1361. &Warning)) {
  1362. FormatMsErrorMessage( ThreadState,
  1363. FileName, LineNumber, Message, Warning );
  1364. return ( TRUE );
  1365. } else {
  1366. return ( FALSE );
  1367. }
  1368. }
  1369. BOOL
  1370. MSPostBuildFilter(
  1371. PTHREADSTATE ThreadState,
  1372. LPSTR p
  1373. )
  1374. {
  1375. LPSTR FileName;
  1376. LPSTR LineNumber;
  1377. LPSTR Message;
  1378. BOOL Warning;
  1379. LPSTR p1;
  1380. FileName = NULL;
  1381. Message = p +10;
  1382. LineNumber = NULL;
  1383. Warning = FALSE;
  1384. if (strstr (p,"ERROR:"))
  1385. FormatMsErrorMessage( ThreadState, FileName, LineNumber, Message, Warning );
  1386. RunningTotals.NumberCompileErrors++;
  1387. ThreadState->BuildMetrics.NumberCompileWarnings++;
  1388. return TRUE;
  1389. }
  1390. //+---------------------------------------------------------------------------
  1391. //
  1392. // Function: ResGenFilter
  1393. //
  1394. // Synopsis: Filters output from the .NET Resource Generator so we know what's happening
  1395. //
  1396. // Arguments: [ThreadState] -- State of thread watching the compiler
  1397. // [p] -- Message we're trying to parse.
  1398. //
  1399. // Returns: TRUE - Message is an error or warning
  1400. // FALSE - Message is not an error or a warning
  1401. //
  1402. // History: 22-Mar-01 sbonev
  1403. //
  1404. //----------------------------------------------------------------------------
  1405. BOOL
  1406. ResGenFilter(
  1407. PTHREADSTATE ThreadState,
  1408. LPSTR p
  1409. )
  1410. {
  1411. if (!strncmp(p, "ResGen: Error: ", 15)) {
  1412. LPSTR LineNumber = _strdup(p);
  1413. LPSTR pch = LineNumber;
  1414. LPCSTR Line = strstr(p, ". Line ");
  1415. LPCSTR Pos = strstr(p, ", position ");
  1416. if (!LineNumber) {
  1417. return FALSE;
  1418. }
  1419. LineNumber[0] = 0;
  1420. // put line,pos info if available
  1421. if (NULL != Line) {
  1422. Line += 7;
  1423. while (isdigit(*Line)) *pch++ = *Line++;
  1424. if (NULL != Pos) {
  1425. Pos += 11;
  1426. *pch++ = ',';
  1427. while (isdigit(*Pos)) *pch++ = *Pos++;
  1428. }
  1429. }
  1430. FormatMsErrorMessage(
  1431. ThreadState,
  1432. ThreadState->ChildCurrentFile,
  1433. LineNumber,
  1434. strlen(ThreadState->ChildCurrentFile) > 0 ? p + 15 : p, // display full message if there is no filename
  1435. FALSE);
  1436. free(LineNumber);
  1437. return TRUE;
  1438. }
  1439. return ( FALSE );
  1440. }
  1441. //+---------------------------------------------------------------------------
  1442. //
  1443. // Function: CScriptFilter
  1444. //
  1445. // Synopsis: Filters output from Windows Script Host so we know what's happening
  1446. //
  1447. // Arguments: [ThreadState] -- State of thread watching the compiler
  1448. // [p] -- Message we're trying to parse.
  1449. //
  1450. // Returns: TRUE - Message is an error or warning
  1451. // FALSE - Message is not an error or a warning
  1452. //
  1453. // History: 22-Mar-01 sbonev
  1454. //
  1455. //----------------------------------------------------------------------------
  1456. BOOL
  1457. CScriptFilter(
  1458. PTHREADSTATE ThreadState,
  1459. LPSTR p
  1460. )
  1461. {
  1462. LPSTR FileName;
  1463. LPSTR LineNumber;
  1464. LPSTR Message;
  1465. BOOL Warning;
  1466. if (NULL != strstr(p, "Microsoft JScript runtime error:") ||
  1467. NULL != strstr(p, "Microsoft JScript compilation error:") ||
  1468. NULL != strstr(p, "Microsoft VBScript runtime error:") ||
  1469. NULL != strstr(p, "Microsoft VBScript compilation error:")) {
  1470. // just display the message
  1471. PassThrough( ThreadState, p, FALSE );
  1472. return TRUE;
  1473. }
  1474. if (MsCompilerFilter( ThreadState, p,
  1475. &FileName,
  1476. &LineNumber,
  1477. &Message,
  1478. &Warning)) {
  1479. FormatMsErrorMessage( ThreadState,
  1480. FileName, LineNumber, Message, Warning );
  1481. return ( TRUE );
  1482. } else {
  1483. return ( FALSE );
  1484. }
  1485. }
  1486. //+---------------------------------------------------------------------------
  1487. //
  1488. // Function: ToolNotFoundFilter
  1489. //
  1490. // Synopsis: Filters output from the build looking for "name not recognized"
  1491. //
  1492. // Arguments: [ThreadState] -- State of thread watching the compiler
  1493. // [p] -- Message we're trying to parse.
  1494. //
  1495. // Returns: TRUE - Message is an error or warning
  1496. // FALSE - Message is not an error or a warning
  1497. //
  1498. // History: 10-Dec-98 patbr Created
  1499. //
  1500. //----------------------------------------------------------------------------
  1501. BOOL
  1502. ToolNotFoundFilter(
  1503. PTHREADSTATE ThreadState,
  1504. LPSTR p
  1505. )
  1506. {
  1507. if ((!strncmp(p, "The name specified is not recognized", 36)) ||
  1508. (!strncmp(p, "internal or external command", 28))) {
  1509. FormatMsErrorMessage( ThreadState,
  1510. ThreadState->ChildCurrentFile, NULL, p, FALSE );
  1511. return TRUE;
  1512. }
  1513. return (FALSE);
  1514. }
  1515. //+---------------------------------------------------------------------------
  1516. //
  1517. // Function: MSToolFilter
  1518. //
  1519. //----------------------------------------------------------------------------
  1520. BOOL
  1521. MSToolFilter(
  1522. PTHREADSTATE ThreadState,
  1523. LPSTR p
  1524. )
  1525. {
  1526. LPSTR FileName;
  1527. LPSTR LineNumber;
  1528. LPSTR Message;
  1529. BOOL Warning;
  1530. if (MsCompilerFilter( ThreadState, p,
  1531. &FileName,
  1532. &LineNumber,
  1533. &Message,
  1534. &Warning
  1535. )
  1536. ) {
  1537. FormatMsErrorMessage( ThreadState,
  1538. FileName, LineNumber, Message, Warning );
  1539. return ( TRUE );
  1540. } else {
  1541. return ( FALSE );
  1542. }
  1543. }
  1544. BOOL
  1545. LinkFilter(
  1546. PTHREADSTATE ThreadState,
  1547. LPSTR p
  1548. );
  1549. //+---------------------------------------------------------------------------
  1550. //
  1551. // Function: LinkFilter1
  1552. //
  1553. //----------------------------------------------------------------------------
  1554. BOOL
  1555. LinkFilter1(
  1556. PTHREADSTATE ThreadState,
  1557. LPSTR p
  1558. )
  1559. {
  1560. LPSTR FileName;
  1561. LPSTR p1;
  1562. char buffer[ 256 ];
  1563. if (p[ strlen( p ) - 1 ] == ':') {
  1564. return ( LinkFilter( ThreadState, p ) );
  1565. }
  1566. p1 = p;
  1567. while (*p1) {
  1568. if (*p1 == '(') {
  1569. *p1++ = 0;
  1570. if (*p1 == '.' && p1[1] == '\\') {
  1571. p1 += 2;
  1572. }
  1573. FileName = p1;
  1574. while (*p1) {
  1575. if (*p1 == ')') {
  1576. *p1++ = 0;
  1577. strcpy( buffer, "L2029: Unresolved external reference to " );
  1578. strncat( buffer,
  1579. ThreadState->UndefinedId,
  1580. sizeof(buffer) - strlen("L2029: Unresolved external reference to "));
  1581. FormatMsErrorMessage( ThreadState, FileName, "1",
  1582. buffer, FALSE
  1583. );
  1584. return ( TRUE );
  1585. } else {
  1586. p1++;
  1587. }
  1588. }
  1589. } else {
  1590. p1++;
  1591. }
  1592. }
  1593. return ( FALSE );
  1594. }
  1595. //+---------------------------------------------------------------------------
  1596. //
  1597. // Function: LinkFilter
  1598. //
  1599. //----------------------------------------------------------------------------
  1600. BOOL
  1601. LinkFilter(
  1602. PTHREADSTATE ThreadState,
  1603. LPSTR p
  1604. )
  1605. {
  1606. LPSTR FileName = NULL;
  1607. LPSTR LineNumber;
  1608. LPSTR Message;
  1609. BOOL Warning;
  1610. LPSTR p1;
  1611. p1 = p;
  1612. while (*p1) {
  1613. if (*p1 == ':') {
  1614. if (p1[-1] == ']') {
  1615. return ( FALSE );
  1616. }
  1617. if (p1[-1] == ' ' && p1[1] == ' ') {
  1618. if (MsCompilerFilter( ThreadState, p,
  1619. &FileName,
  1620. &LineNumber,
  1621. &Message,
  1622. &Warning
  1623. )
  1624. ) {
  1625. if (!Warning || !(_strnicmp(Message, "L4021", 5) ||
  1626. _strnicmp(Message, "L4038", 5) ||
  1627. _strnicmp(Message, "L4046", 5))) {
  1628. if (LineNumber)
  1629. FileName = LineNumber;
  1630. if (FileName && FileName[0] == '.' && FileName[1] == '\\') {
  1631. FileName += 2;
  1632. }
  1633. FormatMsErrorMessage( ThreadState, FileName, "1",
  1634. Message, FALSE );
  1635. return ( TRUE );
  1636. }
  1637. }
  1638. FormatMsErrorMessage( ThreadState, FileName, "1",
  1639. Message, TRUE );
  1640. return ( TRUE );
  1641. }
  1642. if (p1[-1] == ')') {
  1643. p1 -= 11;
  1644. if (p1 > p && !strcmp( p1, " in file(s):" )) {
  1645. strcpy( ThreadState->UndefinedId,
  1646. IsolateFirstToken( &p, ' ' )
  1647. );
  1648. ThreadState->FilterProc = LinkFilter1;
  1649. return ( TRUE );
  1650. }
  1651. }
  1652. return ( FALSE );
  1653. } else {
  1654. p1++;
  1655. }
  1656. }
  1657. return ( FALSE );
  1658. }
  1659. //+---------------------------------------------------------------------------
  1660. //
  1661. // Function: CoffFilter
  1662. //
  1663. //----------------------------------------------------------------------------
  1664. BOOL
  1665. CoffFilter(
  1666. PTHREADSTATE ThreadState,
  1667. LPSTR p
  1668. )
  1669. {
  1670. LPSTR FileName;
  1671. LPSTR LineNumber;
  1672. LPSTR Message;
  1673. BOOL Warning;
  1674. if (MsCompilerFilter( ThreadState, p,
  1675. &FileName,
  1676. &LineNumber,
  1677. &Message,
  1678. &Warning
  1679. )
  1680. ) {
  1681. FormatMsErrorMessage( ThreadState,
  1682. FileName, LineNumber, Message, Warning );
  1683. return ( TRUE );
  1684. } else {
  1685. return ( FALSE );
  1686. }
  1687. }
  1688. //+---------------------------------------------------------------------------
  1689. //
  1690. // Function: ClRiscFilter
  1691. //
  1692. // Synopsis: Risc compiler filter
  1693. //
  1694. // Note: It may be possible to remove this filter.
  1695. //
  1696. //----------------------------------------------------------------------------
  1697. BOOL
  1698. ClRiscFilter(
  1699. PTHREADSTATE ThreadState,
  1700. LPSTR p
  1701. )
  1702. {
  1703. LPSTR FileName;
  1704. LPSTR LineNumber;
  1705. LPSTR Message;
  1706. BOOL Warning;
  1707. LPSTR q;
  1708. if (TestPrefix( &p, "cfe: " )) {
  1709. if (strncmp(p, "Error: ", strlen("Error: ")) == 0) {
  1710. p += strlen("Error: ");
  1711. Warning = FALSE;
  1712. } else if (strncmp(p, "Warning: ", strlen("Warning: ")) == 0) {
  1713. p += strlen("Warning: ");
  1714. Warning = TRUE;
  1715. } else {
  1716. return (FALSE);
  1717. }
  1718. q = p;
  1719. if (p = strstr( p, ".\\\\" )) {
  1720. p += 3;
  1721. } else {
  1722. p = q;
  1723. }
  1724. FileName = p;
  1725. while (*p > ' ') {
  1726. if (*p == ',' || (*p == ':' && *(p+1) == ' ')) {
  1727. *p++ = '\0';
  1728. break;
  1729. }
  1730. p++;
  1731. }
  1732. if (*p != ' ') {
  1733. return ( FALSE );
  1734. }
  1735. *p++ = '\0';
  1736. if (strcmp(p, "line ") == 0) {
  1737. p += strlen("line ");
  1738. }
  1739. LineNumber = p;
  1740. while (*p != '\0' && *p != ':') {
  1741. p++;
  1742. }
  1743. if (*p != ':') {
  1744. return ( FALSE );
  1745. }
  1746. *p++ = '\0';
  1747. if (*p == ' ') {
  1748. Message = p+1;
  1749. ThreadState->LinesToIgnore = 2;
  1750. FormatMsErrorMessage( ThreadState,
  1751. FileName,
  1752. LineNumber,
  1753. Message,
  1754. Warning
  1755. );
  1756. return ( TRUE );
  1757. }
  1758. }
  1759. //
  1760. // If we did not recognize the cfe compiler, pass it to the MS compiler
  1761. // message filter
  1762. //
  1763. return ( C510Filter( ThreadState, p ) );
  1764. }
  1765. //+---------------------------------------------------------------------------
  1766. //
  1767. // Function: MSXSLFilter
  1768. //
  1769. // Synopsis: MSXSL filter
  1770. //
  1771. //----------------------------------------------------------------------------
  1772. BOOL
  1773. MSXSLFilter(
  1774. PTHREADSTATE ThreadState,
  1775. LPSTR p
  1776. )
  1777. {
  1778. LPSTR FirstLine;
  1779. LPSTR FileName;
  1780. LPSTR LineNumber;
  1781. LPSTR ColumnNumber;
  1782. LPSTR Message;
  1783. if (strncmp(p, "Error occurred while ", strlen("Error occurred while ")) == 0) {
  1784. FirstLine = p;
  1785. p = ThreadState->ChildOutput->_ptr + 2;
  1786. if (strncmp(p, "Code: ", strlen("Code: ")) == 0) {
  1787. p = strchr(p, '\r') + 2;
  1788. }
  1789. if (strncmp(p, "URL: ", strlen("URL: ")) == 0) {
  1790. p += strlen("URL: ");
  1791. while (*p == ' ') {
  1792. p++;
  1793. }
  1794. p += strlen("file:///");
  1795. FileName = p;
  1796. while (*p != '\r') {
  1797. if (*p == '/') {
  1798. *p = '\\';
  1799. }
  1800. p++;
  1801. }
  1802. *p = '\0';
  1803. p += 2;
  1804. if (strncmp(p, "Line: ", strlen("Line: ")) == 0) {
  1805. p += strlen("Line: ");
  1806. while (*p == ' ') {
  1807. p++;
  1808. }
  1809. LineNumber = p;
  1810. p = strchr(p, '\r');
  1811. *p = '\0';
  1812. p += 2;
  1813. }
  1814. if (strncmp(p, "Column: ", strlen("Column: ")) == 0) {
  1815. p += strlen("Column: ");
  1816. while (*p == ' ') {
  1817. p++;
  1818. }
  1819. ColumnNumber = p;
  1820. p = strchr(p, '\r');
  1821. *p = '\0';
  1822. p += 2;
  1823. strcat (LineNumber, ", ");
  1824. strcat (LineNumber, ColumnNumber);
  1825. }
  1826. } else {
  1827. FileName = strchr(FirstLine, '\'');
  1828. if (FileName) {
  1829. FileName++;
  1830. *strchr(FileName, '\'') = '\0';
  1831. }
  1832. LineNumber = NULL;
  1833. }
  1834. while (*p == '\n' || *p == '\r' || *p == ' ') {
  1835. p++;
  1836. }
  1837. Message = p;
  1838. while (*p != '\n' && *p != '\r') {
  1839. p++;
  1840. }
  1841. *p = '\0';
  1842. FormatMsErrorMessage (ThreadState, FileName, LineNumber, Message, FALSE);
  1843. } else {
  1844. return (FALSE);
  1845. }
  1846. return ( TRUE );
  1847. }
  1848. //+---------------------------------------------------------------------------
  1849. //
  1850. // Function: MgClientFilter
  1851. //
  1852. //----------------------------------------------------------------------------
  1853. BOOL
  1854. MgClientFilter(
  1855. PTHREADSTATE ThreadState,
  1856. LPSTR p
  1857. )
  1858. {
  1859. return ( PassThrough( ThreadState, p, TRUE ) );
  1860. }
  1861. BOOL fAlreadyUnknown = FALSE;
  1862. //+---------------------------------------------------------------------------
  1863. //
  1864. // Function: DetermineChildState
  1865. //
  1866. // Synopsis: Parse the message given by the compiler (or whatever) and try
  1867. // to figure out what it's doing.
  1868. //
  1869. // Arguments: [ThreadState] -- Current thread state
  1870. // [p] -- New message string
  1871. //
  1872. // Returns: TRUE if we figured it out, FALSE if we didn't recognize
  1873. // anything.
  1874. //
  1875. //----------------------------------------------------------------------------
  1876. BOOL
  1877. DetermineChildState(
  1878. PTHREADSTATE ThreadState,
  1879. LPSTR p
  1880. )
  1881. {
  1882. PFILEREC FileDB;
  1883. char CheckFileName[300];
  1884. LPSTR pCheckFileName;
  1885. LPSTR FileName;
  1886. BOOL fPrintChildState = TRUE;
  1887. //
  1888. // ************ Determine what state the child process is in.
  1889. // (Compiling, linking, running MIDL, etc.)
  1890. //
  1891. if ( TestPrefixPath( &p, "rc ") || TestPrefixPath( &p, "rc.exe ")) {
  1892. if (*p == ':')
  1893. return FALSE; // This is a warning/error string
  1894. if (strstr( p, "amd64") || strstr( p, "AMD64")) {
  1895. ThreadState->ChildTarget = Amd64TargetMachine.Description;
  1896. } else if (strstr( p, "i386") || strstr( p, "I386")) {
  1897. ThreadState->ChildTarget = i386TargetMachine.Description;
  1898. } else if (strstr( p, "ia64") || strstr( p, "IA64")) {
  1899. ThreadState->ChildTarget = ia64TargetMachine.Description;
  1900. } else if (strstr( p, "arm") || strstr( p, "ARM")) {
  1901. ThreadState->ChildTarget = ARMTargetMachine.Description;
  1902. } else {
  1903. ThreadState->ChildTarget = "unknown target";
  1904. }
  1905. ThreadState->FilterProc = MSToolFilter;
  1906. ThreadState->ChildState = STATE_COMPILING;
  1907. ThreadState->ChildFlags = 0;
  1908. strcpy( ThreadState->ChildCurrentFile,
  1909. IsolateLastToken( p, ' ' )
  1910. );
  1911. } else
  1912. if (TestPrefixPath( &p, "rc16 ") ) {
  1913. if (*p == ':')
  1914. return FALSE; // This is a warning/error string
  1915. if (strstr( p, "amd64") || strstr( p, "AMD64")) {
  1916. ThreadState->ChildTarget = Amd64TargetMachine.Description;
  1917. } else if (strstr( p, "i386") || strstr( p, "I386")) {
  1918. ThreadState->ChildTarget = i386TargetMachine.Description;
  1919. } else if (strstr( p, "ia64") || strstr( p, "IA64")) {
  1920. ThreadState->ChildTarget = ia64TargetMachine.Description;
  1921. } else if (strstr( p, "arm") || strstr( p, "ARM")) {
  1922. ThreadState->ChildTarget = ARMTargetMachine.Description;
  1923. } else {
  1924. ThreadState->ChildTarget = "unknown target";
  1925. }
  1926. ThreadState->FilterProc = MSToolFilter;
  1927. ThreadState->ChildState = STATE_COMPILING;
  1928. ThreadState->ChildFlags = 0;
  1929. strcpy( ThreadState->ChildCurrentFile,
  1930. IsolateLastToken( p, ' ' )
  1931. );
  1932. } else
  1933. if ( TestPrefixPath( &p, "cl " ) || TestPrefixPath( &p, "cl.exe " ) ||
  1934. TestPrefixPath( &p, "clarm " ) || TestPrefixPath( &p, "clarm.exe " ) ||
  1935. TestPrefixPath( &p, "covc " ) || TestPrefixPath( &p, "covc.exe " )) {
  1936. LPSTR pch, pch2;
  1937. if (*p == ':')
  1938. return FALSE; // This is a warning/error string
  1939. ThreadState->FilterProc = C510Filter;
  1940. ThreadState->ChildFlags = 0;
  1941. if ( strstr( p, "/WX" ) != NULL || strstr( p, "-WX" ) != NULL) {
  1942. ThreadState->ChildFlags |= FLAGS_WARNINGS_ARE_ERRORS;
  1943. }
  1944. if ((strstr( p, "/EP " ) != NULL) ||
  1945. (strstr( p, "/E " ) != NULL) ||
  1946. (strstr( p, "/P " ) != NULL) ||
  1947. (strstr( p, "-EP " ) != NULL) ||
  1948. (strstr( p, "-E " ) != NULL) ||
  1949. (strstr( p, "-P " ) != NULL)
  1950. ) {
  1951. if (strstr( p, "amd64") || strstr( p, "AMD64")) {
  1952. ThreadState->ChildTarget = Amd64TargetMachine.Description;
  1953. } else if (strstr( p, "i386") || strstr( p, "I386")) {
  1954. ThreadState->ChildTarget = i386TargetMachine.Description;
  1955. } else if (strstr( p, "ia64") || strstr( p, "IA64")) {
  1956. ThreadState->ChildTarget = ia64TargetMachine.Description;
  1957. } else if (strstr( p, "arm") || strstr( p, "ARM")) {
  1958. ThreadState->ChildTarget = ARMTargetMachine.Description;
  1959. } else {
  1960. ThreadState->ChildTarget = "unknown target";
  1961. }
  1962. strcpy( ThreadState->ChildCurrentFile,IsolateLastToken( p, ' ' ) );
  1963. if ( strstr( p, ".s" ) != NULL )
  1964. ThreadState->ChildState = STATE_S_PREPROC;
  1965. else
  1966. ThreadState->ChildState = STATE_C_PREPROC;
  1967. } else
  1968. if ( (pch = strstr( p, "/Yc" )) != NULL ) {
  1969. size_t namelen = strcspn( pch+3, " \t" );
  1970. if (strstr( p, "ia64") || strstr( p, "IA64")) {
  1971. ThreadState->ChildTarget = ia64TargetMachine.Description;
  1972. } else if (strstr( p, "amd64") || strstr( p, "AMD64")) {
  1973. ThreadState->ChildTarget = Amd64TargetMachine.Description;
  1974. } else if (strstr( p, "i386") || strstr( p, "I386")) {
  1975. ThreadState->ChildTarget = i386TargetMachine.Description;
  1976. } else if (strstr( p, "arm") || strstr( p, "ARM")) {
  1977. ThreadState->ChildTarget = ARMTargetMachine.Description;
  1978. } else {
  1979. ThreadState->ChildTarget = "unknown target";
  1980. }
  1981. ThreadState->ChildState = STATE_PRECOMP;
  1982. strncpy( ThreadState->ChildCurrentFile, pch + 3, namelen);
  1983. ThreadState->ChildCurrentFile[namelen] = '\0';
  1984. } else {
  1985. if (strstr( p, "ia64") || strstr( p, "IA64")) {
  1986. ThreadState->ChildTarget = ia64TargetMachine.Description;
  1987. } else if (strstr( p, "amd64") || strstr( p, "AMD64")) {
  1988. ThreadState->ChildTarget = Amd64TargetMachine.Description;
  1989. } else if (strstr( p, "i386") || strstr( p, "I386")) {
  1990. ThreadState->ChildTarget = i386TargetMachine.Description;
  1991. } else if (strstr( p, "arm") || strstr( p, "ARM")) {
  1992. ThreadState->ChildTarget = ARMTargetMachine.Description;
  1993. } else {
  1994. ThreadState->ChildTarget = "unknown target";
  1995. }
  1996. ThreadState->ChildState = STATE_COMPILING;
  1997. strcpy( ThreadState->ChildCurrentFile, "" );
  1998. fPrintChildState = FALSE;
  1999. }
  2000. } else
  2001. if ( TestPrefixPath( &p, "csc " ) || TestPrefixPath( &p, "csc.exe " ) ) {
  2002. ThreadState->ChildState = STATE_LINKING;
  2003. ThreadState->ChildFlags = 0;
  2004. ThreadState->ChildTarget = "all platforms";
  2005. ThreadState->FilterProc = MSCSharpFilter;
  2006. strcpy(ThreadState->ChildCurrentFile, IsolateLastToken(p, ' '));
  2007. } else
  2008. if ( TestPrefixPath( &p, "cl16 " )) {
  2009. if (*p == ':')
  2010. return FALSE; // This is a warning/error string
  2011. ThreadState->FilterProc = C510Filter;
  2012. ThreadState->ChildFlags = 0;
  2013. if (strstr( p, "amd64") || strstr( p, "AMD64")) {
  2014. ThreadState->ChildTarget = Amd64TargetMachine.Description;
  2015. } else if (strstr( p, "i386") || strstr( p, "I386")) {
  2016. ThreadState->ChildTarget = i386TargetMachine.Description;
  2017. } else if (strstr( p, "ia64") || strstr( p, "IA64")) {
  2018. ThreadState->ChildTarget = ia64TargetMachine.Description;
  2019. } else if (strstr( p, "arm") || strstr( p, "ARM")) {
  2020. ThreadState->ChildTarget = ARMTargetMachine.Description;
  2021. } else {
  2022. ThreadState->ChildTarget = "unknown target";
  2023. }
  2024. ThreadState->ChildState = STATE_COMPILING;
  2025. strcpy( ThreadState->ChildCurrentFile,
  2026. IsolateLastToken( p, ' ' ));
  2027. } else
  2028. if (TestPrefixPath( &p, "bc " ) || TestPrefixPath( &p, "bc.exe " )) {
  2029. if (*p == ':')
  2030. return FALSE; // This is a warning/error string
  2031. while (*p == ' ') {
  2032. p++;
  2033. }
  2034. if (IsolateFirstToken( &p, '-' )) {
  2035. if (*p == '\0')
  2036. return FALSE; // This is a warning/error string
  2037. while (*p != 'i') {
  2038. if (!IsolateFirstToken( &p, '-' )) {
  2039. break;
  2040. }
  2041. }
  2042. p++;
  2043. strcpy( ThreadState->ChildCurrentFile,
  2044. IsolateFirstToken( &p, ' ' ));
  2045. ThreadState->ChildFlags = 0;
  2046. ThreadState->ChildTarget = "all platforms";
  2047. ThreadState->FilterProc = MSBCFilter;
  2048. ThreadState->ChildState = STATE_COMPILING;
  2049. }
  2050. } else
  2051. if (TestPrefixPath( &p, "vbc " ) || TestPrefixPath( &p, "vbc.exe " )) {
  2052. if (*p == ':')
  2053. return FALSE; // This is a warning/error string
  2054. while (*p == ' ') {
  2055. p++;
  2056. }
  2057. ThreadState->ChildFlags = 0;
  2058. ThreadState->ChildTarget = "all platforms";
  2059. ThreadState->FilterProc = MSBCFilter;
  2060. ThreadState->ChildState = STATE_COMPILING;
  2061. strcpy( ThreadState->ChildCurrentFile, IsolateLastToken( p, ' ' ) );
  2062. } else
  2063. if (TestPrefixPath( &p, "jvc " ) || TestPrefixPath( &p, "jvc.exe " )) {
  2064. LPSTR pch, pch2;
  2065. if (*p == ':')
  2066. return FALSE; // This is a warning/error string
  2067. while (*p == ' ') {
  2068. p++;
  2069. }
  2070. ThreadState->ChildFlags = 0;
  2071. ThreadState->ChildTarget = "all platforms";
  2072. ThreadState->FilterProc = MSJVCFilter;
  2073. if (((pch = strstr( p, "*.java" )) != NULL ) ||
  2074. (((pch = strstr( p, ".java" )) != NULL ) && ((pch2 = strstr( pch+1, ".java" )) != NULL ))) {
  2075. ThreadState->ChildState = STATE_BATCHCOMPILE;
  2076. // batch compiles will be counted by progress output
  2077. if (getenv("JVC_TERSE") != NULL)
  2078. strcpy( ThreadState->ChildCurrentFile, IsolateLastToken( p, '\\' ) );
  2079. else
  2080. return FALSE;
  2081. } else {
  2082. ThreadState->ChildState = STATE_COMPILING;
  2083. strcpy( ThreadState->ChildCurrentFile, IsolateLastToken( p, ' ' ) );
  2084. }
  2085. } else
  2086. if (TestPrefixPath( &p, "coolc " ) || TestPrefixPath( &p, "coolc.exe " )) {
  2087. LPSTR pch, pch2;
  2088. if (*p == ':')
  2089. return FALSE; // This is a warning/error string
  2090. while (*p == ' ') {
  2091. p++;
  2092. }
  2093. ThreadState->ChildFlags = 0;
  2094. ThreadState->ChildTarget = "all platforms";
  2095. ThreadState->FilterProc = MSCoolFilter;
  2096. if (((pch = strstr( p, "*.cool" )) != NULL ) ||
  2097. (((pch = strstr( p, ".cool" )) != NULL ) && ((pch2 = strstr( pch+1, ".cool" )) != NULL ))) {
  2098. ThreadState->ChildState = STATE_BATCHCOMPILE;
  2099. // batch compiles will be counted by progress output
  2100. return FALSE;
  2101. } else {
  2102. ThreadState->ChildState = STATE_COMPILING;
  2103. strcpy( ThreadState->ChildCurrentFile, IsolateLastToken( p, ' ' ) );
  2104. }
  2105. } else
  2106. if (TestPrefixPath( &p, "resgen " ) || TestPrefixPath( &p, "resgen.exe " ) || TestPrefixPath( &p, "ResGen: Error:" )) {
  2107. //
  2108. // resgen usage:
  2109. // ResGen inputFile.ext [outputFile.ext]
  2110. // no wildcards
  2111. if (*(p-1) == ':') {
  2112. // this is an error string
  2113. if (ThreadState->FilterProc != ResGenFilter) {
  2114. // switch the filter proc if we didn't know that ResGen was running
  2115. ThreadState->FilterProc = ResGenFilter;
  2116. strcpy( ThreadState->ChildCurrentFile, "" );
  2117. }
  2118. return FALSE;
  2119. }
  2120. while (*p == ' ') {
  2121. p++;
  2122. }
  2123. ThreadState->ChildFlags = 0;
  2124. ThreadState->ChildTarget = "all platforms";
  2125. ThreadState->FilterProc = ResGenFilter;
  2126. ThreadState->ChildState = STATE_COMPILING;
  2127. strcpy( ThreadState->ChildCurrentFile, IsolateFirstToken( &p, ' ' ) );
  2128. } else
  2129. if (TestPrefixPath( &p, "cscript " ) || TestPrefixPath( &p, "cscript.exe " )) {
  2130. //
  2131. // cscript usage:
  2132. // CScript [option...] scriptname.extension [option...] [arguments...]
  2133. // options are prefixed with / or -
  2134. ThreadState->ChildFlags = 0;
  2135. ThreadState->ChildTarget = "all platforms";
  2136. ThreadState->ChildState = STATE_VSTOOL;
  2137. ThreadState->FilterProc = CScriptFilter;
  2138. strcpy( ThreadState->ChildCurrentFile, "" ); // don't care about the name; it would be displayed on error
  2139. } else
  2140. if (TestPrefixPath( &p, "docchecker " ) || TestPrefixPath( &p, "docchecker.exe " )) {
  2141. if (*p == ':')
  2142. return FALSE; // This is a warning/error string
  2143. ThreadState->FilterProc = MSToolFilter;
  2144. ThreadState->ChildFlags = 0;
  2145. ThreadState->ChildState = STATE_DOCCHECKING;
  2146. ThreadState->ChildTarget = "all platforms";
  2147. strcpy( ThreadState->ChildCurrentFile, "" );
  2148. } else
  2149. if (TestPrefixPath( &p, "scc " ) || TestPrefixPath( &p, "scc.exe " )) {
  2150. LPSTR pch, pch2;
  2151. if (*p == ':')
  2152. return FALSE; // This is a warning/error string
  2153. while (*p == ' ') {
  2154. p++;
  2155. }
  2156. ThreadState->ChildFlags = 0;
  2157. ThreadState->ChildTarget = "all platforms";
  2158. ThreadState->FilterProc = MSToolFilter;
  2159. if (((pch = strstr( p, "*.sc" )) != NULL ) ||
  2160. (((pch = strstr( p, ".sc" )) != NULL ) && ((pch2 = strstr( pch+1, ".sc" )) != NULL ))) {
  2161. ThreadState->ChildState = STATE_BATCHCOMPILE;
  2162. // batch compiles will be counted by progress output
  2163. return FALSE;
  2164. } else {
  2165. ThreadState->ChildState = STATE_COMPILING;
  2166. strcpy( ThreadState->ChildCurrentFile, IsolateLastToken( p, ' ' ) );
  2167. }
  2168. } else
  2169. if (TestPrefixPath( &p, "wfctosafec " ) || TestPrefixPath( &p, "wfctosafec.exe " )) {
  2170. LPSTR pch, pch2;
  2171. if (*p == ':')
  2172. return FALSE; // This is a warning/error string
  2173. while (*p == ' ') {
  2174. p++;
  2175. }
  2176. ThreadState->ChildFlags = 0;
  2177. ThreadState->ChildTarget = "all platforms";
  2178. ThreadState->FilterProc = MSToolFilter;
  2179. if (((pch = strstr( p, "*.sc" )) != NULL ) ||
  2180. (((pch = strstr( p, ".sc" )) != NULL ) && ((pch2 = strstr( pch+1, ".sc" )) != NULL ))) {
  2181. ThreadState->ChildState = STATE_BATCHCOMPILE;
  2182. // batch compiles will be counted by progress output
  2183. return FALSE;
  2184. } else {
  2185. ThreadState->ChildState = STATE_COMPILING;
  2186. strcpy( ThreadState->ChildCurrentFile, IsolateLastToken( p, ' ' ) );
  2187. }
  2188. } else
  2189. if (TestPrefixPath( &p, "ml " ) || TestPrefixPath( &p, "ml.exe " ) ||
  2190. TestPrefix( &p, "ml64 " ) || TestPrefix( &p, "ml64.exe " )) {
  2191. if (*p == ':')
  2192. return FALSE; // This is a warning/error string
  2193. ThreadState->FilterProc = MSToolFilter;
  2194. ThreadState->ChildState = STATE_ASSEMBLING;
  2195. ThreadState->ChildFlags = 0;
  2196. if (strstr( p, "amd64") || strstr( p, "AMD64")) {
  2197. ThreadState->ChildTarget = Amd64TargetMachine.Description;
  2198. } else if (strstr( p, "i386") || strstr( p, "I386")) {
  2199. ThreadState->ChildTarget = i386TargetMachine.Description;
  2200. } else {
  2201. ThreadState->ChildTarget = "unknown target";
  2202. }
  2203. strcpy( ThreadState->ChildCurrentFile,
  2204. IsolateLastToken( p, ' ' )
  2205. );
  2206. } else
  2207. if (TestPrefixPath( &p, "masm ") || TestPrefixPath( &p, "masm.exe ") ||
  2208. TestPrefixPath( &p, "armasm ") || TestPrefixPath( &p, "armasm.exe ") ||
  2209. TestPrefixPath( &p, "masm386 ") || TestPrefixPath( &p, "masm386.exe ")) {
  2210. if (*p == ':')
  2211. return FALSE; // This is a warning/error string
  2212. ThreadState->FilterProc = MSToolFilter;
  2213. ThreadState->ChildState = STATE_ASSEMBLING;
  2214. ThreadState->ChildFlags = 0;
  2215. if (strstr( p, "amd64") || strstr( p, "AMD64")) {
  2216. ThreadState->ChildTarget = Amd64TargetMachine.Description;
  2217. } else if (strstr( p, "i386") || strstr( p, "I386")) {
  2218. ThreadState->ChildTarget = i386TargetMachine.Description;
  2219. } else if (strstr( p, "ia64") || strstr( p, "IA64")) {
  2220. ThreadState->ChildTarget = ia64TargetMachine.Description;
  2221. } else if (strstr( p, "arm") || strstr( p, "ARM")) {
  2222. ThreadState->ChildTarget = ARMTargetMachine.Description;
  2223. } else {
  2224. ThreadState->ChildTarget = "unknown target";
  2225. }
  2226. if (strstr(p, ",")) {
  2227. strcpy( ThreadState->ChildCurrentFile,
  2228. IsolateLastToken(IsolateFirstToken(&p,','), ' '));
  2229. } else {
  2230. strcpy( ThreadState->ChildCurrentFile,
  2231. IsolateLastToken(IsolateFirstToken(&p,';'), ' '));
  2232. }
  2233. } else
  2234. if (TestPrefixPath( &p, "lib " ) || TestPrefixPath( &p, "lib.exe " )) {
  2235. if (*p == ':')
  2236. return FALSE; // This is a warning/error string
  2237. while (*p == ' ') {
  2238. p++;
  2239. }
  2240. if (strstr( p, "amd64") || strstr( p, "AMD64")) {
  2241. ThreadState->ChildTarget = Amd64TargetMachine.Description;
  2242. } else if (strstr( p, "i386") || strstr( p, "I386")) {
  2243. ThreadState->ChildTarget = i386TargetMachine.Description;
  2244. } else if (strstr( p, "ia64") || strstr( p, "IA64")) {
  2245. ThreadState->ChildTarget = ia64TargetMachine.Description;
  2246. } else if (strstr( p, "arm") || strstr( p, "ARM")) {
  2247. ThreadState->ChildTarget = ARMTargetMachine.Description;
  2248. } else {
  2249. ThreadState->ChildTarget = "unknown target";
  2250. }
  2251. ThreadState->FilterProc = CoffFilter;
  2252. ThreadState->ChildFlags = 0;
  2253. if (TestPrefix( &p, "-out:" )) {
  2254. ThreadState->LinesToIgnore = 1;
  2255. ThreadState->ChildState = STATE_LIBING;
  2256. strcpy( ThreadState->ChildCurrentFile,
  2257. IsolateFirstToken( &p, ' ' )
  2258. );
  2259. } else
  2260. if (TestPrefix( &p, "-def:" )) {
  2261. ThreadState->LinesToIgnore = 1;
  2262. ThreadState->ChildState = STATE_LIBING;
  2263. strcpy( ThreadState->ChildCurrentFile,
  2264. IsolateFirstToken( &p, ' ' )
  2265. );
  2266. if (TestPrefix( &p, "-out:" )) {
  2267. strcpy( ThreadState->ChildCurrentFile,
  2268. IsolateFirstToken( &p, ' ' )
  2269. );
  2270. }
  2271. } else {
  2272. return FALSE;
  2273. }
  2274. } else
  2275. if (TestPrefixPath( &p, "implib " ) || TestPrefixPath( &p, "implib.exe " ) ||
  2276. TestPrefixPath( &p, "lib16 " ) || TestPrefixPath( &p, "lib16.exe " )) {
  2277. if (*p == ':')
  2278. return FALSE; // This is a warning/error string
  2279. while (*p == ' ') {
  2280. p++;
  2281. }
  2282. if (strstr( p, "amd64") || strstr( p, "AMD64")) {
  2283. ThreadState->ChildTarget = Amd64TargetMachine.Description;
  2284. } else if (strstr( p, "i386") || strstr( p, "I386")) {
  2285. ThreadState->ChildTarget = i386TargetMachine.Description;
  2286. } else if (strstr( p, "ia64") || strstr( p, "IA64")) {
  2287. ThreadState->ChildTarget = ia64TargetMachine.Description;
  2288. } else if (strstr( p, "arm") || strstr( p, "ARM")) {
  2289. ThreadState->ChildTarget = ARMTargetMachine.Description;
  2290. } else {
  2291. ThreadState->ChildTarget = "unknown target";
  2292. }
  2293. ThreadState->FilterProc = MSToolFilter;
  2294. ThreadState->ChildFlags = 0;
  2295. ThreadState->ChildState = STATE_LIBING;
  2296. if (strstr(p, ";")) {
  2297. strcpy( ThreadState->ChildCurrentFile,
  2298. IsolateFirstToken( &p, ';' ));
  2299. } else {
  2300. strcpy( ThreadState->ChildCurrentFile,
  2301. IsolateFirstToken( &p, ' ' ));
  2302. }
  2303. } else
  2304. if (TestPrefixPath( &p, "link " ) || TestPrefixPath( &p, "link.exe " ) ||
  2305. TestPrefixPath( &p, "covlink ") || TestPrefixPath( &p, "covlink.exe ")) {
  2306. if (*p == ':')
  2307. return FALSE; // This is a warning/error string
  2308. while (*p == ' ') {
  2309. p++;
  2310. }
  2311. if (strstr( p, "amd64") || strstr( p, "AMD64")) {
  2312. ThreadState->ChildTarget = Amd64TargetMachine.Description;
  2313. } else if (strstr( p, "i386") || strstr( p, "I386")) {
  2314. ThreadState->ChildTarget = i386TargetMachine.Description;
  2315. } else if (strstr( p, "ia64") || strstr( p, "IA64")) {
  2316. ThreadState->ChildTarget = ia64TargetMachine.Description;
  2317. } else if (strstr( p, "arm") || strstr( p, "ARM")) {
  2318. ThreadState->ChildTarget = ARMTargetMachine.Description;
  2319. } else {
  2320. ThreadState->ChildTarget = "unknown target";
  2321. }
  2322. ThreadState->FilterProc = CoffFilter;
  2323. ThreadState->ChildFlags = 0;
  2324. if (TestPrefix( &p, "-out:" )) {
  2325. ThreadState->LinesToIgnore = 2;
  2326. ThreadState->ChildState = STATE_LINKING;
  2327. strcpy( ThreadState->ChildCurrentFile,
  2328. IsolateFirstToken( &p, ' ' )
  2329. );
  2330. }
  2331. } else
  2332. if (TestPrefixPath( &p, "link16" ) ) {
  2333. if (*p == ':')
  2334. return FALSE; // This is a warning/error string
  2335. while (*p == ' ') {
  2336. p++;
  2337. }
  2338. if (strstr( p, "amd64") || strstr( p, "AMD64")) {
  2339. ThreadState->ChildTarget = Amd64TargetMachine.Description;
  2340. } else if (strstr( p, "i386") || strstr( p, "I386")) {
  2341. ThreadState->ChildTarget = i386TargetMachine.Description;
  2342. } else if (strstr( p, "ia64") || strstr( p, "IA64")) {
  2343. ThreadState->ChildTarget = ia64TargetMachine.Description;
  2344. } else if (strstr( p, "arm") || strstr( p, "ARM")) {
  2345. ThreadState->ChildTarget = ARMTargetMachine.Description;
  2346. } else {
  2347. ThreadState->ChildTarget = "unknown target";
  2348. }
  2349. ThreadState->FilterProc = LinkFilter;
  2350. ThreadState->ChildFlags = 0;
  2351. ThreadState->ChildState = STATE_LINKING;
  2352. p = IsolateLastToken(p, ' ');
  2353. if (strstr(p, ";")) {
  2354. strcpy( ThreadState->ChildCurrentFile,
  2355. IsolateFirstToken( &p, ';' ));
  2356. } else {
  2357. strcpy( ThreadState->ChildCurrentFile,
  2358. IsolateFirstToken( &p, ',' ));
  2359. }
  2360. } else
  2361. if ( TestPrefixPath( &p, "bscmake " ) || TestPrefixPath( &p, "bscmake.exe " )) {
  2362. LPSTR pch, pch2;
  2363. if (*p == ':')
  2364. return FALSE; // This is a warning/error string
  2365. ThreadState->FilterProc = MSToolFilter;
  2366. ThreadState->ChildFlags = 0;
  2367. ThreadState->ChildState = STATE_BSCMAKING;
  2368. ThreadState->ChildTarget = "all platforms";
  2369. if ( (pch = strstr( p, "/o" )) != NULL ) {
  2370. size_t namelen;
  2371. pch2 = pch + 3;
  2372. if ( *pch2 == '"' )
  2373. pch2++;
  2374. namelen = strcspn( pch2, " \t\"" );
  2375. strncpy( ThreadState->ChildCurrentFile, pch2, namelen );
  2376. ThreadState->ChildCurrentFile[namelen] = '\0';
  2377. }
  2378. } else
  2379. if (TestPrefixPath( &p, "icl ")) {
  2380. while (*p == ' ') {
  2381. p++;
  2382. }
  2383. ThreadState->ChildState = STATE_COMPILING;
  2384. ThreadState->ChildFlags = 0;
  2385. ThreadState->ChildTarget = ia64TargetMachine.Description;
  2386. ThreadState->FilterProc = C510Filter;
  2387. strcpy( ThreadState->ChildCurrentFile,
  2388. IsolateLastToken( p, ' ' )
  2389. );
  2390. } else
  2391. if (TestPrefixPath( &p, "mktyplib " ) || TestPrefixPath( &p, "mktyplib.exe " )) {
  2392. if (*p == ':')
  2393. return FALSE; // This is a warning/error string
  2394. while (*p == ' ') {
  2395. p++;
  2396. }
  2397. ThreadState->ChildState = STATE_MKTYPLIB;
  2398. ThreadState->ChildFlags = 0;
  2399. ThreadState->ChildTarget = "all platforms";
  2400. ThreadState->FilterProc = C510Filter;
  2401. strcpy( ThreadState->ChildCurrentFile,
  2402. IsolateLastToken( p, ' ' )
  2403. );
  2404. } else
  2405. if (TestPrefix( &p, "MC: Compiling " )) {
  2406. if (*p == ':')
  2407. return FALSE; // This is a warning/error string
  2408. while (*p == ' ') {
  2409. p++;
  2410. }
  2411. ThreadState->ChildState = STATE_MC;
  2412. ThreadState->ChildFlags = 0;
  2413. ThreadState->ChildTarget = "all platforms";
  2414. ThreadState->FilterProc = C510Filter;
  2415. strcpy( ThreadState->ChildCurrentFile,
  2416. IsolateLastToken( p, ' ' )
  2417. );
  2418. } else
  2419. if (TestPrefixPath( &p, "midl " ) || TestPrefixPath( &p, "midl.exe " )) {
  2420. if (*p == ':')
  2421. return FALSE; // This is a warning/error string
  2422. while (*p == ' ') {
  2423. p++;
  2424. }
  2425. ThreadState->ChildState = STATE_MIDL;
  2426. ThreadState->ChildFlags = 0;
  2427. ThreadState->ChildTarget = "all platforms";
  2428. ThreadState->FilterProc = C510Filter;
  2429. strcpy( ThreadState->ChildCurrentFile,
  2430. IsolateLastToken( p, ' ' )
  2431. );
  2432. } else
  2433. if (TestPrefixPath( &p, "asn1 " )) {
  2434. if (*p == ':')
  2435. return FALSE; // This is a warning/error string
  2436. while (*p == ' ') {
  2437. p++;
  2438. }
  2439. ThreadState->ChildState = STATE_ASN;
  2440. ThreadState->ChildFlags = 0;
  2441. ThreadState->ChildTarget = "all platforms";
  2442. ThreadState->FilterProc = C510Filter;
  2443. strcpy(ThreadState->ChildCurrentFile, IsolateLastToken(p, ' '));
  2444. } else
  2445. if (TestPrefix( &p, "Build_Status " )) {
  2446. while (*p == ' ') {
  2447. p++;
  2448. }
  2449. ThreadState->ChildState = STATE_STATUS;
  2450. ThreadState->ChildFlags = 0;
  2451. ThreadState->ChildTarget = "";
  2452. ThreadState->FilterProc = C510Filter;
  2453. strcpy( ThreadState->ChildCurrentFile, "" );
  2454. }
  2455. else
  2456. if (TestPrefixPath( &p, "binplace " )) {
  2457. if (*p == ':')
  2458. return FALSE; // This is a warning/error string
  2459. RunningTotals.NumberBinplaces++;
  2460. ThreadState->BuildMetrics.NumberBinplaces++;
  2461. while (*p == ' ') {
  2462. p++;
  2463. }
  2464. // If this is a standard link/binplace step, don't tell the
  2465. // user what's going on, just pass any errors/warnings to
  2466. // the output. If this is a straight binplace, list the state.
  2467. if (ThreadState->ChildState == STATE_LINKING) {
  2468. ThreadState->ChildState = STATE_BINPLACE;
  2469. ThreadState->ChildFlags = 0;
  2470. ThreadState->FilterProc = MSToolFilter;
  2471. return TRUE;
  2472. } else {
  2473. ThreadState->ChildState = STATE_BINPLACE;
  2474. ThreadState->ChildFlags = 0;
  2475. ThreadState->FilterProc = MSToolFilter;
  2476. strcpy( ThreadState->ChildCurrentFile, IsolateLastToken( p, ' ' ) );
  2477. }
  2478. }
  2479. else
  2480. if (TestPrefixPath( &p, "ctc " ) || TestPrefixPath( &p, "ctc.exe " )) {
  2481. size_t namelen;
  2482. if (*p == ':')
  2483. return FALSE; // This is a warning/error string
  2484. while (*p == ' ') {
  2485. p++;
  2486. }
  2487. ThreadState->ChildState = STATE_CTCOMPILING;
  2488. ThreadState->ChildFlags = 0;
  2489. ThreadState->ChildTarget = "all platforms";
  2490. ThreadState->FilterProc = MSToolFilter;
  2491. while (*p == '-') {
  2492. p = p + strcspn( p, " \t" );
  2493. while (*p == ' ')
  2494. p++;
  2495. }
  2496. namelen = strcspn( p, " \t" );
  2497. strncpy( ThreadState->ChildCurrentFile, p, namelen );
  2498. ThreadState->ChildCurrentFile[namelen] = '\0';
  2499. }
  2500. else
  2501. if (TestPrefixPath( &p, "idheader " )) {
  2502. size_t namelen;
  2503. if (*p == ':')
  2504. return FALSE; // This is a warning/error string
  2505. while (*p == ' ') {
  2506. p++;
  2507. }
  2508. ThreadState->ChildState = STATE_VSTOOL;
  2509. ThreadState->ChildFlags = 0;
  2510. ThreadState->ChildTarget = "all platforms";
  2511. ThreadState->FilterProc = MSToolFilter;
  2512. namelen = strcspn( p, " \t" );
  2513. strncpy( ThreadState->ChildCurrentFile, p, namelen );
  2514. ThreadState->ChildCurrentFile[namelen] = '\0';
  2515. }
  2516. else
  2517. if (TestPrefixPath( &p, "bison ")) {
  2518. if (*p == ':')
  2519. return FALSE; // This is a warning/error string
  2520. while (*p == ' ') {
  2521. p++;
  2522. }
  2523. ThreadState->ChildState = STATE_VSTOOL;
  2524. ThreadState->ChildFlags = 0;
  2525. ThreadState->ChildTarget = "all platforms";
  2526. ThreadState->FilterProc = MSToolFilter;
  2527. strcpy( ThreadState->ChildCurrentFile, IsolateLastToken( p, ' ' ) );
  2528. } else
  2529. if ((TestPrefix( &p, "packthem " )) || (TestPrefix( &p, "..\\packthem " ))) {
  2530. if (*p == ':')
  2531. return FALSE; // This is a warning/error string
  2532. while (*p == ' ')
  2533. p++;
  2534. ThreadState->ChildTarget = i386TargetMachine.Description;
  2535. ThreadState->FilterProc = CoffFilter;
  2536. ThreadState->ChildFlags = 0;
  2537. ThreadState->ChildState = STATE_PACKING;
  2538. if (TestPrefix( &p, "-o" )) {
  2539. strcpy( ThreadState->ChildCurrentFile, IsolateFirstToken( &p, ' ' ));
  2540. }
  2541. }
  2542. else
  2543. if (TestPrefixPath( &p, "gnu_bison ")) {
  2544. if (*p == ':')
  2545. return FALSE; // This is a warning/error string
  2546. while (*p == ' ') {
  2547. p++;
  2548. }
  2549. ThreadState->ChildState = STATE_VSTOOL;
  2550. ThreadState->ChildFlags = 0;
  2551. ThreadState->ChildTarget = "all platforms";
  2552. ThreadState->FilterProc = BisonFilter;
  2553. strcpy( ThreadState->ChildCurrentFile, IsolateLastToken( p, ' ' ) );
  2554. }
  2555. else
  2556. if ( TestPrefixPath( &p, "vsautodoc " ) || TestPrefixPath( &p, "vsautodoc.exe " )) {
  2557. LPSTR pch, pch2;
  2558. if (*p == ':')
  2559. return FALSE; // This is a warning/error string
  2560. ThreadState->FilterProc = MSToolFilter;
  2561. ThreadState->ChildFlags = 0;
  2562. ThreadState->ChildState = STATE_AUTODOCING;
  2563. ThreadState->ChildTarget = "all platforms";
  2564. if ( (pch = strstr( p, "/o" )) != NULL ) {
  2565. size_t namelen;
  2566. pch2 = pch + 3;
  2567. if ( *pch2 == '"' )
  2568. pch2++;
  2569. namelen = strcspn( pch2, " \t\"" );
  2570. strncpy( ThreadState->ChildCurrentFile, pch2, namelen );
  2571. ThreadState->ChildCurrentFile[namelen] = '\0';
  2572. }
  2573. }
  2574. else
  2575. if (TestPrefix( &p, "msxsl " ) ) {
  2576. if (*p == ':')
  2577. return FALSE; // This is a warning/error string
  2578. while (*p == ' ') {
  2579. p++;
  2580. }
  2581. ThreadState->FilterProc = MSXSLFilter;
  2582. ThreadState->ChildFlags = 0;
  2583. ThreadState->ChildTarget = "all platforms";
  2584. ThreadState->ChildState = STATE_COMPILING;
  2585. strcpy( ThreadState->ChildCurrentFile, IsolateFirstToken( &p, ' ' ));
  2586. } else
  2587. if (TestPrefix( &p, "POSTBUILD:" ) ) {
  2588. ThreadState->ChildState = STATE_POSTBUILD;
  2589. ThreadState->ChildFlags = 0;
  2590. ThreadState->ChildTarget = "all platforms";
  2591. ThreadState->FilterProc = MSPostBuildFilter;
  2592. return FALSE;
  2593. } else
  2594. if (ThreadState->ChildState == STATE_BATCHCOMPILE) {
  2595. if (strstr( p, "integral type to pointer") ||
  2596. strstr( p, "this conversion is possible") ||
  2597. strstr( p, "void cannot be converted") ||
  2598. strstr( p, "Compiling...") ||
  2599. strstr( p, "Generating Code...") ||
  2600. strstr( p, "Parsing ") ||
  2601. strstr( p, "Loading class:") ||
  2602. strstr( p, "Generating file "))
  2603. return FALSE; // This is a warning/error/info string
  2604. if (strstr( p, ".c") && !strchr( p, ' ') && !strchr( p, ':'))
  2605. strcpy( ThreadState->ChildCurrentFile, p ); // C/C++ compile
  2606. else if (strstr( p, ".java") && strstr( p, "Compiling ")) {
  2607. if (getenv("JVC_TERSE") != NULL) {
  2608. RunningTotals.NumberCompiles++;
  2609. ThreadState->BuildMetrics.NumberCompiles++;
  2610. return FALSE;
  2611. } else {
  2612. strcpy( ThreadState->ChildCurrentFile, IsolateLastToken( p, '\\' ) ); // Java compile
  2613. }
  2614. } else
  2615. return FALSE;
  2616. }
  2617. else {
  2618. return FALSE;
  2619. }
  2620. //
  2621. // ***************** Set the Thread State according to what we determined.
  2622. //
  2623. FileName = ThreadState->ChildCurrentFile;
  2624. // make sure directories match to trailing backslash
  2625. strcpy(CheckFileName, FileName);
  2626. pCheckFileName = CheckFileName;
  2627. if (TestPrefix( &pCheckFileName, CurrentDirectory )) {
  2628. if (*pCheckFileName == '\\') {
  2629. FileName += (pCheckFileName - CheckFileName) + 1;
  2630. }
  2631. if (TestPrefix( &pCheckFileName, ThreadState->ChildCurrentDirectory )) {
  2632. if (*pCheckFileName == '\\') {
  2633. FileName += (pCheckFileName - CheckFileName) + 1;
  2634. }
  2635. }
  2636. strcpy( ThreadState->ChildCurrentFile, FileName );
  2637. }
  2638. FileDB = NULL;
  2639. if (ThreadState->ChildState == STATE_LIBING) {
  2640. RunningTotals.NumberLibraries++;
  2641. ThreadState->BuildMetrics.NumberLibraries++;
  2642. } else
  2643. if (ThreadState->ChildState == STATE_LINKING) {
  2644. RunningTotals.NumberLinks++;
  2645. ThreadState->BuildMetrics.NumberLinks++;
  2646. } else
  2647. if (ThreadState->ChildState == STATE_BSCMAKING) {
  2648. RunningTotals.NumberBSCMakes++;
  2649. ThreadState->BuildMetrics.NumberBSCMakes++;
  2650. } else
  2651. if ((ThreadState->ChildState == STATE_STATUS) ||
  2652. // Don't need to do anything here - binplace count already handled above
  2653. (ThreadState->ChildState == STATE_BINPLACE) ||
  2654. (ThreadState->ChildState == STATE_UNKNOWN)) {
  2655. ; // Do nothing.
  2656. } else {
  2657. if (ThreadState->CompileDirDB) {
  2658. RunningTotals.NumberCompiles++;
  2659. ThreadState->BuildMetrics.NumberCompiles++;
  2660. CopyString(ThreadState->ChildCurrentFile, ThreadState->ChildCurrentFile, TRUE);
  2661. if (!fQuicky) {
  2662. FileDB = FindSourceFileDB(
  2663. ThreadState->CompileDirDB,
  2664. ThreadState->ChildCurrentFile,
  2665. NULL);
  2666. }
  2667. }
  2668. }
  2669. if (strstr(ThreadState->ChildCurrentFile, ".cxx") ||
  2670. strstr(ThreadState->ChildCurrentFile, ".cpp")) {
  2671. ThreadState->ChildFlags |= FLAGS_CXX_FILE;
  2672. }
  2673. if (fPrintChildState)
  2674. PrintChildState(ThreadState, p, FileDB);
  2675. return TRUE;
  2676. }
  2677. //+---------------------------------------------------------------------------
  2678. //
  2679. // Function: PrintChildState
  2680. //
  2681. // Synopsis:
  2682. //
  2683. // Arguments: [ThreadState] -- Current thread state
  2684. //
  2685. // Returns: TRUE if we figured it out, FALSE if we didn't recognize
  2686. // anything.
  2687. //
  2688. //----------------------------------------------------------------------------
  2689. void
  2690. PrintChildState(
  2691. PTHREADSTATE ThreadState,
  2692. LPSTR p,
  2693. PFILEREC FileDB
  2694. )
  2695. {
  2696. USHORT SaveCol;
  2697. USHORT SaveRow;
  2698. USHORT SaveRowTop;
  2699. BOOL fStatusOutput = FALSE;
  2700. char buffer[ DB_MAX_PATH_LENGTH ];
  2701. LONG FilesLeft;
  2702. LONG LinesLeft;
  2703. ULONG LinesPerSecond;
  2704. ULONG SecondsLeft;
  2705. ULONG PercentDone;
  2706. //
  2707. // *********************** Print the thread state to the screen
  2708. //
  2709. if (ThreadState->IsStdErrTty) {
  2710. GetScreenSize(ThreadState);
  2711. assert(ThreadState->cColTotal != 0);
  2712. assert(ThreadState->cRowTotal != 0);
  2713. if (fStatus) {
  2714. GetCursorPosition(&SaveRow, &SaveCol, &SaveRowTop);
  2715. // Clear row for process message
  2716. ClearRows (ThreadState,
  2717. (USHORT) (SaveRowTop + ThreadState->ThreadIndex - 1),
  2718. 1,
  2719. StatusCell);
  2720. // Clear row for status message
  2721. ClearRows (ThreadState,
  2722. (USHORT) (SaveRowTop + NumberProcesses),
  2723. 1,
  2724. StatusCell);
  2725. // Make sure there's still some room at the bottom
  2726. if (SaveRow == LastRow(ThreadState)) {
  2727. USHORT RowTop = 1 + SaveRowTop + (USHORT) NumberProcesses + 1;
  2728. MoveRectangleUp (
  2729. RowTop, // Top
  2730. 0, // Left
  2731. LastRow(ThreadState), // Bottom
  2732. LastCol(ThreadState), // Right
  2733. 1, // NumRow
  2734. ScreenCell); // FillCell
  2735. SaveRow--;
  2736. }
  2737. SetCursorPosition(
  2738. (USHORT) (SaveRowTop + ThreadState->ThreadIndex - 1),
  2739. 0);
  2740. fStatusOutput = TRUE;
  2741. }
  2742. }
  2743. if (szBuildTag) {
  2744. sprintf(buffer, "%s: ", szBuildTag);
  2745. WriteTTY(ThreadState, buffer, fStatusOutput);
  2746. }
  2747. if (fParallel && !fNoThreadIndex) {
  2748. sprintf(buffer, "%d>", ThreadState->ThreadIndex);
  2749. WriteTTY(ThreadState, buffer, fStatusOutput);
  2750. }
  2751. if (ThreadState->ChildState == STATE_UNKNOWN) {
  2752. if (!fAlreadyUnknown) {
  2753. WriteTTY(
  2754. ThreadState,
  2755. "Processing Unknown item(s)...\r\n",
  2756. fStatusOutput);
  2757. fAlreadyUnknown = TRUE;
  2758. }
  2759. } else
  2760. if (ThreadState->ChildState == STATE_STATUS) {
  2761. WriteTTY(ThreadState, p, fStatusOutput);
  2762. WriteTTY(ThreadState, "\r\n", fStatusOutput);
  2763. } else {
  2764. fAlreadyUnknown = FALSE;
  2765. WriteTTY(ThreadState, States[ThreadState->ChildState], fStatusOutput);
  2766. WriteTTY(ThreadState, " - ", fStatusOutput);
  2767. WriteTTY(ThreadState, FormatPathName(ThreadState->ChildCurrentDirectory, ThreadState->ChildCurrentFile), fStatusOutput);
  2768. WriteTTY(ThreadState, " for ", fStatusOutput);
  2769. WriteTTY(ThreadState, ThreadState->ChildTarget, fStatusOutput);
  2770. WriteTTY(ThreadState, "\r\n", fStatusOutput);
  2771. if (fXMLOutput || fXMLFragment) {
  2772. XMLThreadInitBuffer(ThreadState);
  2773. if (PXMLThreadStates[ThreadState->XMLThreadIndex]->fXMLInAction) {
  2774. // check for action errors or warnings
  2775. if (ThreadState->BuildMetrics.NumberActErrors || ThreadState->BuildMetrics.NumberActWarnings) {
  2776. sprintf(szXMLBuffer, "<ACTIONSUMMARY ");
  2777. if (ThreadState->BuildMetrics.NumberActErrors) {
  2778. sprintf(szXMLBuffer + strlen(szXMLBuffer), " ERRORS=\"%d\"", ThreadState->BuildMetrics.NumberActErrors);
  2779. }
  2780. if (ThreadState->BuildMetrics.NumberActWarnings) {
  2781. sprintf(szXMLBuffer + strlen(szXMLBuffer), " WARNINGS=\"%d\"", ThreadState->BuildMetrics.NumberActWarnings);
  2782. }
  2783. strcat(szXMLBuffer, "/>");
  2784. XMLThreadWrite(ThreadState, szXMLBuffer);
  2785. }
  2786. XMLThreadCloseTag(ThreadState, "ACTION");
  2787. PXMLThreadStates[ThreadState->XMLThreadIndex]->fXMLInAction = FALSE;
  2788. }
  2789. XMLThreadOpenTag(ThreadState, "ACTION", "TYPE=\"%s\" FILE=\"%s\" TARGET=\"%s\"", States[ThreadState->ChildState], ThreadState->ChildCurrentFile, ThreadState->ChildTarget);
  2790. PXMLThreadStates[ThreadState->XMLThreadIndex]->fXMLInAction = TRUE;
  2791. }
  2792. ThreadState->BuildMetrics.NumberDirActions++;
  2793. ThreadState->BuildMetrics.NumberActErrors = 0;
  2794. ThreadState->BuildMetrics.NumberActWarnings = 0;
  2795. }
  2796. if (StartCompileTime) {
  2797. ElapsedCompileTime += (ULONG)(time(NULL) - StartCompileTime);
  2798. }
  2799. if (FileDB != NULL) {
  2800. StartCompileTime = time(NULL);
  2801. } else {
  2802. StartCompileTime = 0L;
  2803. }
  2804. //
  2805. // ****************** Update the status line
  2806. //
  2807. if (ThreadState->IsStdErrTty) {
  2808. assert(ThreadState->cColTotal != 0);
  2809. assert(ThreadState->cRowTotal != 0);
  2810. if (fStatus) {
  2811. if (FileDB != NULL) {
  2812. FilesLeft = TotalFilesToCompile - TotalFilesCompiled;
  2813. if (FilesLeft < 0) {
  2814. FilesLeft = 0;
  2815. }
  2816. LinesLeft = TotalLinesToCompile - TotalLinesCompiled;
  2817. if (LinesLeft < 0) {
  2818. LinesLeft = 0;
  2819. PercentDone = 99;
  2820. } else if (TotalLinesToCompile != 0) {
  2821. if (TotalLinesCompiled > 20000000L) {
  2822. int TLC = TotalLinesCompiled / 100;
  2823. int TLTC = TotalLinesToCompile / 100;
  2824. PercentDone = (TLC * 100L)/TLTC;
  2825. } else
  2826. PercentDone = (TotalLinesCompiled * 100L)/TotalLinesToCompile;
  2827. } else {
  2828. PercentDone = 0;
  2829. }
  2830. if (ElapsedCompileTime != 0) {
  2831. LinesPerSecond = TotalLinesCompiled / ElapsedCompileTime;
  2832. } else {
  2833. LinesPerSecond = 0;
  2834. }
  2835. if (LinesPerSecond != 0) {
  2836. SecondsLeft = LinesLeft / LinesPerSecond;
  2837. } else {
  2838. SecondsLeft = LinesLeft / DEFAULT_LPS;
  2839. }
  2840. sprintf(
  2841. buffer,
  2842. "%2d%% done. %4ld %sLPS Time Left:%s Files: %d %sLines: %s\r\n",
  2843. PercentDone,
  2844. LinesPerSecond,
  2845. fStatusTree? "T" : "",
  2846. FormatTime(SecondsLeft),
  2847. FilesLeft,
  2848. fStatusTree? "Total " : "",
  2849. FormatNumber(LinesLeft));
  2850. SetCursorPosition((USHORT) (SaveRowTop + NumberProcesses), 0);
  2851. WriteTTY(ThreadState, buffer, fStatusOutput);
  2852. }
  2853. SetCursorPosition(SaveRow, SaveCol);
  2854. }
  2855. }
  2856. //
  2857. // ***************** Keep track of how many files have been compiled.
  2858. //
  2859. if (ThreadState->ChildState == STATE_COMPILING ||
  2860. ThreadState->ChildState == STATE_ASSEMBLING ||
  2861. ThreadState->ChildState == STATE_MKTYPLIB ||
  2862. ThreadState->ChildState == STATE_MIDL ||
  2863. ThreadState->ChildState == STATE_ASN ||
  2864. (FileDB != NULL && ThreadState->ChildState == STATE_PRECOMP)) {
  2865. TotalFilesCompiled++;
  2866. }
  2867. if (FileDB != NULL) {
  2868. TotalLinesCompiled += FileDB->TotalSourceLines;
  2869. }
  2870. }
  2871. //+---------------------------------------------------------------------------
  2872. //
  2873. // Function: ProcessLine
  2874. //
  2875. // Synopsis: Watch the lines coming from the thread for special strings.
  2876. //
  2877. //----------------------------------------------------------------------------
  2878. BOOL
  2879. ProcessLine(
  2880. PTHREADSTATE ThreadState,
  2881. LPSTR p
  2882. )
  2883. {
  2884. LPSTR p1;
  2885. while (*p <= ' ') {
  2886. if (!*p) {
  2887. return ( FALSE );
  2888. } else {
  2889. p++;
  2890. }
  2891. }
  2892. p1 = p;
  2893. while (*p1) {
  2894. if (*p1 == '\r')
  2895. break;
  2896. else
  2897. p1++;
  2898. }
  2899. *p1 = '\0';
  2900. p1 = p;
  2901. if (TestPrefix( &p1, "Stop." )) {
  2902. return ( TRUE );
  2903. }
  2904. // Stop multithread access to shared:
  2905. // database
  2906. // window
  2907. // compilation stats
  2908. EnterCriticalSection(&TTYCriticalSection);
  2909. if (TestPrefix( &p1, "nmake :" )) {
  2910. PassThrough( ThreadState, p, FALSE );
  2911. } else
  2912. if (TestPrefix( &p1, "BUILDMSG: " )) {
  2913. if (TestPrefix(&p1, "Warning")) {
  2914. PassThrough(ThreadState, p, TRUE);
  2915. } else {
  2916. WriteTTY(ThreadState, p, TRUE);
  2917. WriteTTY(ThreadState, "\r\n", TRUE);
  2918. }
  2919. } else
  2920. if (ThreadState->LinesToIgnore) {
  2921. ThreadState->LinesToIgnore--;
  2922. } else {
  2923. if ( !DetermineChildState( ThreadState, p ) ) {
  2924. if (!ToolNotFoundFilter( ThreadState, p )) {
  2925. if (ThreadState->FilterProc != NULL) {
  2926. (*ThreadState->FilterProc)( ThreadState, p );
  2927. }
  2928. }
  2929. }
  2930. }
  2931. if (fXMLVerboseOutput) {
  2932. XMLThreadWrite(ThreadState, "<RAW MESSAGE=\"%s\"/>\r\n", XMLEncodeBuiltInEntitiesCopy(p, szXMLBuffer));
  2933. }
  2934. LeaveCriticalSection(&TTYCriticalSection);
  2935. return ( FALSE );
  2936. }
  2937. //+---------------------------------------------------------------------------
  2938. //
  2939. // Function: FilterThread
  2940. //
  2941. // Synopsis: Capture the output of the thread and process it.
  2942. //
  2943. //----------------------------------------------------------------------------
  2944. VOID
  2945. FilterThread(
  2946. PTHREADSTATE ThreadState
  2947. )
  2948. {
  2949. UINT CountBytesRead;
  2950. LPSTR StartPointer = NULL;
  2951. LPSTR EndPointer;
  2952. LPSTR NewPointer;
  2953. ULONG BufSize = 512;
  2954. UINT uThreadIdLen = 0;
  2955. AllocMem(BufSize, &StartPointer, MT_THREADFILTER);
  2956. while (TRUE) {
  2957. EndPointer = StartPointer;
  2958. do {
  2959. if (BufSize - (EndPointer-StartPointer) < 512) {
  2960. AllocMem(BufSize*2, &NewPointer, MT_THREADFILTER);
  2961. RtlCopyMemory(
  2962. NewPointer,
  2963. StartPointer,
  2964. EndPointer - StartPointer + 1); // copy null byte, too
  2965. EndPointer += NewPointer - StartPointer;
  2966. FreeMem(&StartPointer, MT_THREADFILTER);
  2967. StartPointer = NewPointer;
  2968. BufSize *= 2;
  2969. }
  2970. if (!fgets(EndPointer, 512, ThreadState->ChildOutput)) {
  2971. if (errno != 0)
  2972. BuildError("Pipe read failed - errno = %d\r\n", errno);
  2973. FreeMem(&StartPointer, MT_THREADFILTER);
  2974. return;
  2975. }
  2976. CountBytesRead = strlen(EndPointer);
  2977. EndPointer = EndPointer + CountBytesRead;
  2978. } while (CountBytesRead == 511 && EndPointer[-1] != '\n');
  2979. CountBytesRead = (UINT)(EndPointer - StartPointer);
  2980. if (fErrorLog && CountBytesRead) {
  2981. if (fParallel && !fNoThreadIndex) {
  2982. char buffer[50];
  2983. sprintf(buffer, "%d>", ThreadState->ThreadIndex);
  2984. fwrite(buffer, 1, strlen(buffer), LogFile);
  2985. }
  2986. fwrite(StartPointer, 1, CountBytesRead, LogFile);
  2987. }
  2988. if (ProcessLine(ThreadState, StartPointer)) {
  2989. FreeMem(&StartPointer, MT_THREADFILTER);
  2990. return;
  2991. }
  2992. }
  2993. }
  2994. //+---------------------------------------------------------------------------
  2995. //
  2996. // Function: ExecuteProgram
  2997. //
  2998. // Synopsis: Spawn a new thread to execute the given program and filter
  2999. // its output.
  3000. //
  3001. // Arguments: [ProgramName] --
  3002. // [CommandLine] --
  3003. // [MoreCommandLine] --
  3004. // [MustBeSynchronous] -- For synchronous operation on a
  3005. // multi-processor machine.
  3006. // [XMLDir] -- For XML output only - the name of
  3007. // the directory processed.
  3008. // [XMLAction] -- For XML output only - what we are
  3009. // doing with the directory.
  3010. //
  3011. // Returns: ERROR_SUCCESS, ERROR_NOTENOUGHMEMORY, or return code from
  3012. // PipeSpawnClose.
  3013. //
  3014. // Notes: On a multiprocessor machine, this will spawn a new thread
  3015. // and then return, letting the thread run asynchronously. Use
  3016. // WaitForParallelThreads() to ensure all threads are finished.
  3017. // By default, this routine will spawn as many threads as the
  3018. // machine has processors. This can be overridden with the -M
  3019. // option.
  3020. //
  3021. //----------------------------------------------------------------------------
  3022. char ExecuteProgramCmdLine[ 1024 ];
  3023. UINT
  3024. ExecuteProgram(
  3025. LPSTR ProgramName,
  3026. LPSTR CommandLine,
  3027. LPSTR MoreCommandLine,
  3028. BOOL MustBeSynchronous,
  3029. LPCSTR XMLDir,
  3030. LPCSTR XMLAction)
  3031. {
  3032. LPSTR p;
  3033. UINT rc;
  3034. THREADSTATE *ThreadState;
  3035. UINT OldErrorMode;
  3036. DWORD dwStartTime;
  3037. AllocMem(sizeof(THREADSTATE), &ThreadState, MT_THREADSTATE);
  3038. memset(ThreadState, 0, sizeof(*ThreadState));
  3039. ThreadState->ChildState = STATE_UNKNOWN;
  3040. ThreadState->ChildTarget = "Unknown Target";
  3041. ThreadState->IsStdErrTty = (BOOL) _isatty(_fileno(stderr));
  3042. ThreadState->CompileDirDB = CurrentCompileDirDB;
  3043. ThreadState->FilterProc = NMakeFilter;
  3044. if (ThreadState->IsStdErrTty) {
  3045. GetScreenSize(ThreadState);
  3046. assert(ThreadState->cColTotal != 0);
  3047. assert(ThreadState->cRowTotal != 0);
  3048. // We're displaying to the screen, so initialize the console.
  3049. if (!fConsoleInitialized) {
  3050. StatusCell[1] =
  3051. BACKGROUND_RED |
  3052. FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN |
  3053. FOREGROUND_INTENSITY;
  3054. ReadConsoleCells(ScreenCell, sizeof(ScreenCell), 2, 0);
  3055. // If we stumbled upon an old Status line in row 2 of the window,
  3056. // try the current row to avoid using the Status line background
  3057. // colors for fill when scrolling.
  3058. if (ScreenCell[1] == StatusCell[1]) {
  3059. USHORT Row, Col;
  3060. GetCursorPosition(&Row, &Col, NULL);
  3061. ReadConsoleCells(ScreenCell, sizeof(ScreenCell), Row, 0);
  3062. }
  3063. ScreenCell[0] = StatusCell[0] = ' ';
  3064. GetConsoleMode(GetStdHandle(STD_ERROR_HANDLE), &OldConsoleMode);
  3065. NewConsoleMode = OldConsoleMode;
  3066. fConsoleInitialized = TRUE;
  3067. }
  3068. if (fStatus) {
  3069. NewConsoleMode = OldConsoleMode & ~(ENABLE_WRAP_AT_EOL_OUTPUT);
  3070. } else {
  3071. NewConsoleMode = OldConsoleMode | ENABLE_WRAP_AT_EOL_OUTPUT;
  3072. }
  3073. SetConsoleMode(GetStdHandle(STD_ERROR_HANDLE), NewConsoleMode);
  3074. } else {
  3075. ThreadState->cRowTotal = 0;
  3076. ThreadState->cColTotal = 0;
  3077. }
  3078. p = ThreadState->ChildCurrentDirectory;
  3079. GetCurrentDirectory(sizeof(ThreadState->ChildCurrentDirectory), p);
  3080. if (TestPrefix(&p, CurrentDirectory)) {
  3081. if (*p == '\\') {
  3082. p++;
  3083. }
  3084. strcpy(ThreadState->ChildCurrentDirectory, p);
  3085. }
  3086. if (ThreadState->ChildCurrentDirectory[0]) {
  3087. strcat(ThreadState->ChildCurrentDirectory, "\\");
  3088. }
  3089. sprintf(
  3090. ExecuteProgramCmdLine,
  3091. "%s %s%s",
  3092. ProgramName,
  3093. CommandLine,
  3094. MoreCommandLine);
  3095. LogMsg("'%s %s%s'\r\n", ProgramName, CommandLine, MoreCommandLine);
  3096. if (fParallel && !MustBeSynchronous) {
  3097. PPARALLEL_CHILD ChildData;
  3098. DWORD i;
  3099. DWORD ThreadId;
  3100. AllocMem(sizeof(PARALLEL_CHILD), &ChildData, MT_CHILDDATA);
  3101. strcpy(ChildData->ExecuteProgramCmdLine,ExecuteProgramCmdLine);
  3102. ChildData->ThreadState = ThreadState;
  3103. if (ThreadsStarted < NumberProcesses) {
  3104. if (ThreadsStarted == 0) {
  3105. AllocMem(
  3106. sizeof(HANDLE) * NumberProcesses,
  3107. (VOID **) &WorkerThreads,
  3108. MT_THREADHANDLES);
  3109. AllocMem(
  3110. sizeof(HANDLE) * NumberProcesses,
  3111. (VOID **) &WorkerEvents,
  3112. MT_EVENTHANDLES);
  3113. }
  3114. WorkerEvents[ThreadsStarted] = CreateEvent(NULL,
  3115. FALSE,
  3116. FALSE,
  3117. NULL);
  3118. ChildData->Event = WorkerEvents[ThreadsStarted];
  3119. ThreadState->ThreadIndex = ThreadsStarted+1;
  3120. if (fXMLOutput || fXMLFragment) {
  3121. ThreadState->XMLThreadIndex = ThreadState->ThreadIndex;
  3122. }
  3123. /*
  3124. Thread-specific directory message that associates directory to build thread.
  3125. */
  3126. if (fParallel && !fNoThreadIndex && ThreadState->CompileDirDB && fErrorLog) {
  3127. char buffer[500];
  3128. ThreadState->CompileDirDB;
  3129. sprintf(buffer, "%d>BUILDMSG: Processing %s\r\n", ThreadState->ThreadIndex,
  3130. ThreadState->CompileDirDB->Name);
  3131. fwrite(buffer, 1, strlen(buffer), LogFile);
  3132. }
  3133. if (fXMLOutput || fXMLFragment) {
  3134. char buffer[1024];
  3135. char* pszRelPath = (char*)XMLDir;
  3136. if (TestPrefix(&pszRelPath, CurrentDirectory) && (*pszRelPath == '\\')) pszRelPath++;
  3137. if (strlen(pszRelPath) == 0) {
  3138. pszRelPath = ".\\";
  3139. }
  3140. strcpy(buffer, "CMDLINE=\"");
  3141. XMLEncodeBuiltInEntitiesCopy(ExecuteProgramCmdLine, buffer+strlen(buffer));
  3142. sprintf(buffer + strlen(buffer), "\" ACTION=\"%s\" FULLPATH=\"%s\" RELPATH=\"%s\"", XMLAction, ThreadState->ChildCurrentDirectory, pszRelPath);
  3143. XMLThreadInitBuffer(ThreadState);
  3144. XMLThreadOpenTag(ThreadState, "DIR", buffer);
  3145. dwStartTime = GetTickCount();
  3146. }
  3147. memset(&(ThreadState->BuildMetrics), 0, sizeof(BUILDMETRICS));
  3148. WorkerThreads[ThreadsStarted] = CreateThread(NULL,
  3149. 0,
  3150. (LPTHREAD_START_ROUTINE)ParallelChildStart,
  3151. ChildData,
  3152. 0,
  3153. &ThreadId);
  3154. if ((WorkerThreads[ThreadsStarted] == NULL) ||
  3155. (WorkerEvents[ThreadsStarted] == NULL)) {
  3156. FreeMem(&ChildData, MT_CHILDDATA);
  3157. FreeMem(&ThreadState, MT_THREADSTATE);
  3158. return (ERROR_NOT_ENOUGH_MEMORY);
  3159. } else {
  3160. WaitForSingleObject(WorkerEvents[ThreadsStarted],INFINITE);
  3161. ++ThreadsStarted;
  3162. }
  3163. } else {
  3164. //
  3165. // Wait for a thread to complete before starting
  3166. // the next one.
  3167. //
  3168. i = WaitForMultipleObjects(NumberProcesses,
  3169. WorkerThreads,
  3170. FALSE,
  3171. INFINITE);
  3172. CloseHandle(WorkerThreads[i]);
  3173. ChildData->Event = WorkerEvents[i];
  3174. ThreadState->ThreadIndex = i+1;
  3175. if (fXMLOutput || fXMLFragment) {
  3176. ThreadState->XMLThreadIndex = ThreadState->ThreadIndex;
  3177. }
  3178. /*
  3179. Thread-specific directory message that associates directory to build thread.
  3180. */
  3181. if (fParallel && !fNoThreadIndex && ThreadState->CompileDirDB && fErrorLog) {
  3182. char buffer[500];
  3183. ThreadState->CompileDirDB;
  3184. sprintf(buffer, "%d>BUILDMSG: Processing %s\r\n", ThreadState->ThreadIndex,
  3185. ThreadState->CompileDirDB->Name);
  3186. fwrite(buffer, 1, strlen(buffer), LogFile);
  3187. }
  3188. if (fXMLOutput || fXMLFragment) {
  3189. char buffer[1024];
  3190. char* pszRelPath = (char*)XMLDir;
  3191. if (TestPrefix(&pszRelPath, CurrentDirectory) && (*pszRelPath == '\\')) pszRelPath++;
  3192. if (strlen(pszRelPath) == 0) {
  3193. pszRelPath = ".\\";
  3194. }
  3195. strcpy(buffer, "CMDLINE=\"");
  3196. XMLEncodeBuiltInEntitiesCopy(ExecuteProgramCmdLine, buffer+strlen(buffer));
  3197. sprintf(buffer + strlen(buffer), "\" ACTION=\"%s\" FULLPATH=\"%s\" RELPATH=\"%s\"", XMLAction, XMLDir, pszRelPath);
  3198. XMLThreadInitBuffer(ThreadState);
  3199. XMLThreadOpenTag(ThreadState, "DIR", buffer);
  3200. dwStartTime = GetTickCount();
  3201. }
  3202. memset(&(ThreadState->BuildMetrics), 0, sizeof(BUILDMETRICS));
  3203. WorkerThreads[i] = CreateThread(NULL,
  3204. 0,
  3205. (LPTHREAD_START_ROUTINE)ParallelChildStart,
  3206. ChildData,
  3207. 0,
  3208. &ThreadId);
  3209. if (WorkerThreads[i] == NULL) {
  3210. FreeMem(&ChildData, MT_CHILDDATA);
  3211. FreeMem(&ThreadState, MT_THREADSTATE);
  3212. return (ERROR_NOT_ENOUGH_MEMORY);
  3213. } else {
  3214. WaitForSingleObject(WorkerEvents[i],INFINITE);
  3215. }
  3216. }
  3217. return (ERROR_SUCCESS);
  3218. } else {
  3219. //
  3220. // Synchronous operation
  3221. //
  3222. StartCompileTime = 0L;
  3223. ThreadState->ThreadIndex = 1;
  3224. if (fXMLOutput || fXMLFragment) {
  3225. // the synchronized directories are always processed by the main thread
  3226. ThreadState->XMLThreadIndex = 0;
  3227. }
  3228. //
  3229. // Disable child error popups in child processes.
  3230. //
  3231. if (fClean) {
  3232. OldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX );
  3233. }
  3234. /*
  3235. Thread-specific directory message that associates directory to build thread.
  3236. */
  3237. if (fParallel && !fNoThreadIndex && ThreadState->CompileDirDB && fErrorLog) {
  3238. char buffer[500];
  3239. ThreadState->CompileDirDB;
  3240. sprintf(buffer, "%d>BUILDMSG: Processing %s\r\n", ThreadState->ThreadIndex,
  3241. ThreadState->CompileDirDB->Name);
  3242. fwrite(buffer, 1, strlen(buffer), LogFile);
  3243. }
  3244. if (fXMLOutput || fXMLFragment) {
  3245. char buffer[1024];
  3246. char* pszRelPath = (char*)XMLDir;
  3247. if (TestPrefix(&pszRelPath, CurrentDirectory) && (*pszRelPath == '\\')) pszRelPath++;
  3248. if (strlen(pszRelPath) == 0) {
  3249. pszRelPath = ".\\";
  3250. }
  3251. strcpy(buffer, "CMDLINE=\"");
  3252. XMLEncodeBuiltInEntitiesCopy(ExecuteProgramCmdLine, buffer+strlen(buffer));
  3253. sprintf(buffer + strlen(buffer), "\" ACTION=\"%s\" FULLPATH=\"%s\" RELPATH=\"%s\"", XMLAction, XMLDir, pszRelPath);
  3254. XMLThreadInitBuffer(ThreadState);
  3255. XMLThreadOpenTag(ThreadState, "DIR", buffer);
  3256. dwStartTime = GetTickCount();
  3257. }
  3258. memset(&(ThreadState->BuildMetrics), 0, sizeof(BUILDMETRICS));
  3259. ThreadState->ChildOutput = PipeSpawn( ExecuteProgramCmdLine );
  3260. if (fClean) {
  3261. SetErrorMode( OldErrorMode );
  3262. }
  3263. rc = ERROR_SUCCESS;
  3264. if (ThreadState->ChildOutput == NULL) {
  3265. BuildError(
  3266. "Exec of '%s' failed - errno = %d\r\n",
  3267. ExecuteProgramCmdLine,
  3268. errno);
  3269. } else {
  3270. FilterThread( ThreadState );
  3271. if (StartCompileTime) {
  3272. ElapsedCompileTime += (ULONG)(time(NULL) - StartCompileTime);
  3273. }
  3274. rc = PipeSpawnClose( ThreadState->ChildOutput );
  3275. if (rc == -1) {
  3276. BuildError("Child Terminate failed - errno = %d\r\n", errno);
  3277. } else
  3278. if (rc)
  3279. BuildColorError(COLOR_ERROR, "%s failed - rc = %d\r\n", ProgramName, rc);
  3280. }
  3281. if (fXMLOutput || fXMLFragment) {
  3282. XMLEnterCriticalSection();
  3283. AddBuildMetrics(&PassMetrics, &ThreadState->BuildMetrics);
  3284. if (PXMLThreadStates[ThreadState->XMLThreadIndex]->fXMLInAction) {
  3285. // check for action errors or warnings
  3286. if (ThreadState->BuildMetrics.NumberActErrors || ThreadState->BuildMetrics.NumberActWarnings) {
  3287. sprintf(szXMLBuffer, "<ACTIONSUMMARY ");
  3288. if (ThreadState->BuildMetrics.NumberActErrors) {
  3289. sprintf(szXMLBuffer + strlen(szXMLBuffer), " ERRORS=\"%d\"", ThreadState->BuildMetrics.NumberActErrors);
  3290. }
  3291. if (ThreadState->BuildMetrics.NumberActWarnings) {
  3292. sprintf(szXMLBuffer + strlen(szXMLBuffer), " WARNINGS=\"%d\"", ThreadState->BuildMetrics.NumberActWarnings);
  3293. }
  3294. strcat(szXMLBuffer, "/>");
  3295. XMLThreadWrite(ThreadState, szXMLBuffer);
  3296. }
  3297. XMLThreadCloseTag(ThreadState, "ACTION");
  3298. PXMLThreadStates[ThreadState->XMLThreadIndex]->fXMLInAction = FALSE;
  3299. }
  3300. sprintf(szXMLBuffer, "ELAPSED=\"%s\" ACTIONS=\"%d\" ", FormatElapsedTime(dwStartTime), ThreadState->BuildMetrics.NumberDirActions);
  3301. strcat(szXMLBuffer, XMLBuildMetricsString(&(ThreadState->BuildMetrics)));
  3302. XMLThreadWrite(ThreadState, "<DIRSUMMARY %s/>", szXMLBuffer);
  3303. XMLThreadCloseTag(ThreadState, "DIR");
  3304. if (fXMLFragment) {
  3305. LPSTR pszStart;
  3306. PXMLTHREADSTATE XMLState = PXMLThreadStates[ThreadState->XMLThreadIndex];
  3307. XMLScanBackTag(XMLState->XMLBuffer + XMLState->iXMLBufferPos, XMLState->XMLBuffer, &pszStart);
  3308. XMLWriteDirFragmentFile(
  3309. strlen(ThreadState->ChildCurrentDirectory) == 0 ? ".\\" : ThreadState->ChildCurrentDirectory,
  3310. pszStart, XMLState->XMLBuffer + XMLState->iXMLBufferPos - pszStart);
  3311. }
  3312. XMLThreadReleaseBuffer(ThreadState);
  3313. XMLUpdateEndTag(FALSE);
  3314. XMLLeaveCriticalSection();
  3315. }
  3316. if (ThreadState->IsStdErrTty) {
  3317. RestoreConsoleMode();
  3318. }
  3319. FreeMem(&ThreadState, MT_THREADSTATE);
  3320. //
  3321. // Signal completion
  3322. //
  3323. if (CurrentCompileDirDB && (CurrentCompileDirDB->DirFlags & DIRDB_SYNC_PRODUCES)) {
  3324. PDEPENDENCY_WAIT Wait;
  3325. PDEPENDENCY Dependency;
  3326. PLIST_ENTRY List;
  3327. PLIST_ENTRY WaitList;
  3328. List = CurrentCompileDirDB->Produces.Flink;
  3329. while (List != &CurrentCompileDirDB->Produces) {
  3330. Dependency = CONTAINING_RECORD(List, DEPENDENCY, DependencyList);
  3331. List = List->Flink;
  3332. Dependency->Done = TRUE;
  3333. SetEvent(Dependency->hEvent);
  3334. }
  3335. }
  3336. return ( rc );
  3337. }
  3338. }
  3339. //+---------------------------------------------------------------------------
  3340. //
  3341. // Function: WaitForParallelThreads
  3342. //
  3343. // Synopsis: Wait for all threads to finish before returning.
  3344. //
  3345. //----------------------------------------------------------------------------
  3346. VOID
  3347. WaitForParallelThreads(
  3348. IN PDIRREC Dir
  3349. )
  3350. {
  3351. CheckAllConsumer(TRUE);
  3352. if (fParallel) {
  3353. WaitForMultipleObjects(ThreadsStarted,
  3354. WorkerThreads,
  3355. TRUE,
  3356. INFINITE);
  3357. while (ThreadsStarted) {
  3358. CloseHandle(WorkerThreads[--ThreadsStarted]);
  3359. CloseHandle(WorkerEvents[ThreadsStarted]);
  3360. }
  3361. if (WorkerThreads != NULL) {
  3362. FreeMem((VOID **) &WorkerThreads, MT_THREADHANDLES);
  3363. FreeMem((VOID **) &WorkerEvents, MT_EVENTHANDLES);
  3364. }
  3365. }
  3366. }
  3367. //+---------------------------------------------------------------------------
  3368. //
  3369. // Function: ParallelChildStart
  3370. //
  3371. // Synopsis: Function that is run once for each thread.
  3372. //
  3373. // Arguments: [Data] -- Data given to CreateThread.
  3374. //
  3375. //----------------------------------------------------------------------------
  3376. DWORD
  3377. ParallelChildStart(
  3378. PPARALLEL_CHILD Data
  3379. )
  3380. {
  3381. UINT OldErrorMode;
  3382. UINT rc;
  3383. DWORD dwStartTime = GetTickCount();
  3384. PDIRREC DirDB;
  3385. //
  3386. // Disable child error popups
  3387. //
  3388. if (fClean) {
  3389. OldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX );
  3390. }
  3391. Data->ThreadState->ChildOutput = PipeSpawn(Data->ExecuteProgramCmdLine);
  3392. if (fClean) {
  3393. SetErrorMode(OldErrorMode);
  3394. }
  3395. //
  3396. // Poke the event to indicate that the child process has
  3397. // started and it is ok for the main thread to change
  3398. // the current directory.
  3399. //
  3400. SetEvent(Data->Event);
  3401. if (Data->ThreadState->ChildOutput==NULL) {
  3402. BuildError(
  3403. "Exec of '%s' failed - errno = %d\r\n",
  3404. ExecuteProgramCmdLine,
  3405. errno);
  3406. } else {
  3407. FilterThread(Data->ThreadState);
  3408. rc = PipeSpawnClose(Data->ThreadState->ChildOutput);
  3409. if (rc == -1) {
  3410. BuildError("Child terminate failed - errno = %d\r\n", errno);
  3411. } else {
  3412. if (rc) {
  3413. BuildError("%s failed - rc = %d\r\n", Data->ExecuteProgramCmdLine, rc);
  3414. }
  3415. }
  3416. }
  3417. if (Data->ThreadState->IsStdErrTty) {
  3418. RestoreConsoleMode();
  3419. }
  3420. if (fXMLOutput || fXMLFragment) {
  3421. XMLEnterCriticalSection();
  3422. AddBuildMetrics(&PassMetrics, &Data->ThreadState->BuildMetrics);
  3423. if (PXMLThreadStates[Data->ThreadState->XMLThreadIndex]->fXMLInAction) {
  3424. // check for action errors or warnings
  3425. if (Data->ThreadState->BuildMetrics.NumberActErrors || Data->ThreadState->BuildMetrics.NumberActWarnings) {
  3426. sprintf(szXMLBuffer, "<ACTIONSUMMARY ");
  3427. if (Data->ThreadState->BuildMetrics.NumberActErrors) {
  3428. sprintf(szXMLBuffer + strlen(szXMLBuffer), " ERRORS=\"%d\"", Data->ThreadState->BuildMetrics.NumberActErrors);
  3429. }
  3430. if (Data->ThreadState->BuildMetrics.NumberActWarnings) {
  3431. sprintf(szXMLBuffer + strlen(szXMLBuffer), " WARNINGS=\"%d\"", Data->ThreadState->BuildMetrics.NumberActWarnings);
  3432. }
  3433. strcat(szXMLBuffer, "/>");
  3434. XMLThreadWrite(Data->ThreadState, szXMLBuffer);
  3435. }
  3436. XMLThreadCloseTag(Data->ThreadState, "ACTION");
  3437. PXMLThreadStates[Data->ThreadState->XMLThreadIndex]->fXMLInAction = FALSE;
  3438. }
  3439. sprintf(szXMLBuffer, "ELAPSED=\"%s\" ACTIONS=\"%d\" ", FormatElapsedTime(dwStartTime), Data->ThreadState->BuildMetrics.NumberDirActions);
  3440. strcat(szXMLBuffer, XMLBuildMetricsString(&(Data->ThreadState->BuildMetrics)));
  3441. XMLThreadWrite(Data->ThreadState, "<DIRSUMMARY %s/>", szXMLBuffer);
  3442. XMLThreadCloseTag(Data->ThreadState, "DIR");
  3443. if (fXMLFragment) {
  3444. LPSTR pszStart;
  3445. PXMLTHREADSTATE XMLState = PXMLThreadStates[Data->ThreadState->XMLThreadIndex];
  3446. XMLScanBackTag(XMLState->XMLBuffer + XMLState->iXMLBufferPos, XMLState->XMLBuffer, &pszStart);
  3447. XMLWriteDirFragmentFile(
  3448. strlen(Data->ThreadState->ChildCurrentDirectory) == 0 ? ".\\" : Data->ThreadState->ChildCurrentDirectory,
  3449. pszStart, XMLState->XMLBuffer + XMLState->iXMLBufferPos - pszStart);
  3450. }
  3451. XMLThreadReleaseBuffer(Data->ThreadState);
  3452. XMLUpdateEndTag(FALSE);
  3453. XMLLeaveCriticalSection();
  3454. }
  3455. //
  3456. // Signal completion
  3457. //
  3458. DirDB=Data->ThreadState->CompileDirDB;
  3459. if (DirDB &&
  3460. (DirDB->DirFlags & DIRDB_SYNC_PRODUCES)) {
  3461. PDEPENDENCY_WAIT Wait;
  3462. PDEPENDENCY Dependency;
  3463. PLIST_ENTRY List;
  3464. PLIST_ENTRY WaitList;
  3465. List = DirDB->Produces.Flink;
  3466. while (List != &DirDB->Produces) {
  3467. Dependency = CONTAINING_RECORD(List, DEPENDENCY, DependencyList);
  3468. List = List->Flink;
  3469. Dependency->Done = TRUE;
  3470. SetEvent(Dependency->hEvent);
  3471. }
  3472. }
  3473. FreeMem(&Data->ThreadState, MT_THREADSTATE);
  3474. FreeMem(&Data, MT_CHILDDATA);
  3475. return (rc);
  3476. }
  3477. //+---------------------------------------------------------------------------
  3478. //
  3479. // Function: ClearRows
  3480. //
  3481. //----------------------------------------------------------------------------
  3482. VOID
  3483. ClearRows(
  3484. THREADSTATE *ThreadState,
  3485. USHORT Top,
  3486. USHORT NumRows,
  3487. BYTE *Cell)
  3488. {
  3489. COORD Coord;
  3490. DWORD NumWritten;
  3491. Coord.X = 0;
  3492. Coord.Y = Top;
  3493. FillConsoleOutputCharacter(
  3494. GetStdHandle(STD_ERROR_HANDLE),
  3495. Cell[0],
  3496. ThreadState->cColTotal * NumRows,
  3497. Coord,
  3498. &NumWritten);
  3499. FillConsoleOutputAttribute(
  3500. GetStdHandle(STD_ERROR_HANDLE),
  3501. (WORD) Cell[1],
  3502. ThreadState->cColTotal * NumRows,
  3503. Coord,
  3504. &NumWritten);
  3505. }
  3506. //+---------------------------------------------------------------------------
  3507. //
  3508. // Function: GetScreenSize
  3509. //
  3510. //----------------------------------------------------------------------------
  3511. VOID
  3512. GetScreenSize(THREADSTATE *ThreadState)
  3513. {
  3514. CONSOLE_SCREEN_BUFFER_INFO csbi;
  3515. if (!GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &csbi)) {
  3516. ThreadState->cRowTotal = 25;
  3517. ThreadState->cColTotal = 80;
  3518. } else {
  3519. ThreadState->cRowTotal = csbi.srWindow.Bottom + 1;
  3520. ThreadState->cColTotal = csbi.dwSize.X;
  3521. }
  3522. }
  3523. //+---------------------------------------------------------------------------
  3524. //
  3525. // Function: GetCursorPosition
  3526. //
  3527. //----------------------------------------------------------------------------
  3528. VOID
  3529. GetCursorPosition(
  3530. USHORT *pRow,
  3531. USHORT *pCol,
  3532. USHORT *pRowTop)
  3533. {
  3534. CONSOLE_SCREEN_BUFFER_INFO csbi;
  3535. GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &csbi);
  3536. *pRow = csbi.dwCursorPosition.Y;
  3537. *pCol = csbi.dwCursorPosition.X;
  3538. if (pRowTop != NULL) {
  3539. *pRowTop = csbi.srWindow.Top;
  3540. }
  3541. }
  3542. //+---------------------------------------------------------------------------
  3543. //
  3544. // Function: SetCursorPosition
  3545. //
  3546. //----------------------------------------------------------------------------
  3547. VOID
  3548. SetCursorPosition(USHORT Row, USHORT Col)
  3549. {
  3550. COORD Coord;
  3551. Coord.X = Col;
  3552. Coord.Y = Row;
  3553. SetConsoleCursorPosition(GetStdHandle(STD_ERROR_HANDLE), Coord);
  3554. }
  3555. //+---------------------------------------------------------------------------
  3556. //
  3557. // Function: WriteConsoleCells
  3558. //
  3559. //----------------------------------------------------------------------------
  3560. VOID
  3561. WriteConsoleCells(
  3562. LPSTR String,
  3563. USHORT StringLength,
  3564. USHORT Row,
  3565. USHORT Col,
  3566. BYTE *Attribute)
  3567. {
  3568. CONSOLE_SCREEN_BUFFER_INFO csbi;
  3569. DWORD NumWritten;
  3570. WORD OldAttribute;
  3571. COORD StartCoord;
  3572. //
  3573. // Get current default attribute and save it.
  3574. //
  3575. GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &csbi);
  3576. OldAttribute = csbi.wAttributes;
  3577. //
  3578. // Set the default attribute to the passed parameter, along with
  3579. // the cursor position.
  3580. //
  3581. if ((BYTE) OldAttribute != *Attribute) {
  3582. SetConsoleTextAttribute(
  3583. GetStdHandle(STD_ERROR_HANDLE),
  3584. (WORD) *Attribute);
  3585. }
  3586. StartCoord.X = Col;
  3587. StartCoord.Y = Row;
  3588. SetConsoleCursorPosition(GetStdHandle(STD_ERROR_HANDLE), StartCoord);
  3589. //
  3590. // Write the passed string at the current cursor position, using the
  3591. // new default attribute.
  3592. //
  3593. WriteFile(
  3594. GetStdHandle(STD_ERROR_HANDLE),
  3595. String,
  3596. StringLength,
  3597. &NumWritten,
  3598. NULL);
  3599. //
  3600. // Restore previous default attribute.
  3601. //
  3602. if ((BYTE) OldAttribute != *Attribute) {
  3603. SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), OldAttribute);
  3604. }
  3605. }
  3606. //+---------------------------------------------------------------------------
  3607. //
  3608. // Function: MoveRectangleUp
  3609. //
  3610. //----------------------------------------------------------------------------
  3611. VOID
  3612. MoveRectangleUp (
  3613. USHORT Top,
  3614. USHORT Left,
  3615. USHORT Bottom,
  3616. USHORT Right,
  3617. USHORT NumRow,
  3618. BYTE *FillCell)
  3619. {
  3620. SMALL_RECT ScrollRectangle;
  3621. COORD DestinationOrigin;
  3622. CHAR_INFO Fill;
  3623. ScrollRectangle.Left = Left;
  3624. ScrollRectangle.Top = Top;
  3625. ScrollRectangle.Right = Right;
  3626. ScrollRectangle.Bottom = Bottom;
  3627. DestinationOrigin.X = Left;
  3628. DestinationOrigin.Y = Top - NumRow;
  3629. Fill.Char.AsciiChar = FillCell[0];
  3630. Fill.Attributes = (WORD) FillCell[1];
  3631. ScrollConsoleScreenBuffer(
  3632. GetStdHandle(STD_ERROR_HANDLE),
  3633. &ScrollRectangle,
  3634. NULL,
  3635. DestinationOrigin,
  3636. &Fill);
  3637. }
  3638. //+---------------------------------------------------------------------------
  3639. //
  3640. // Function: ReadConsoleCells
  3641. //
  3642. //----------------------------------------------------------------------------
  3643. VOID
  3644. ReadConsoleCells(
  3645. BYTE *ScreenCell,
  3646. USHORT cb,
  3647. USHORT Row,
  3648. USHORT Column)
  3649. {
  3650. COORD BufferSize, BufferCoord;
  3651. SMALL_RECT ReadRegion;
  3652. CHAR_INFO CharInfo[1], *p;
  3653. USHORT CountCells;
  3654. CountCells = cb >> 1;
  3655. assert(CountCells * sizeof(CHAR_INFO) <= sizeof(CharInfo));
  3656. ReadRegion.Top = Row;
  3657. ReadRegion.Left = Column;
  3658. ReadRegion.Bottom = Row;
  3659. ReadRegion.Right = Column + CountCells - 1;
  3660. BufferSize.X = 1;
  3661. BufferSize.Y = CountCells;
  3662. BufferCoord.X = 0;
  3663. BufferCoord.Y = 0;
  3664. ReadConsoleOutput(
  3665. GetStdHandle(STD_ERROR_HANDLE),
  3666. CharInfo,
  3667. BufferSize,
  3668. BufferCoord,
  3669. &ReadRegion);
  3670. p = CharInfo;
  3671. while (CountCells--) {
  3672. *ScreenCell++ = p->Char.AsciiChar;
  3673. *ScreenCell++ = (BYTE) p->Attributes;
  3674. p++;
  3675. }
  3676. }
  3677. //+---------------------------------------------------------------------------
  3678. //
  3679. // Function: ClearLine
  3680. //
  3681. //----------------------------------------------------------------------------
  3682. VOID
  3683. ClearLine(VOID)
  3684. {
  3685. CONSOLE_SCREEN_BUFFER_INFO csbi;
  3686. COORD Coord;
  3687. DWORD NumWritten;
  3688. GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &csbi);
  3689. Coord.Y = csbi.dwCursorPosition.Y;
  3690. Coord.X = csbi.dwCursorPosition.X = 0;
  3691. FillConsoleOutputCharacter(
  3692. GetStdHandle(STD_ERROR_HANDLE),
  3693. ' ',
  3694. csbi.dwSize.X,
  3695. csbi.dwCursorPosition,
  3696. &NumWritten);
  3697. SetConsoleCursorPosition(GetStdHandle(STD_ERROR_HANDLE), Coord);
  3698. fLineCleared = TRUE;
  3699. }
  3700. // PipeSpawn variables. We can get away with one copy per thread.
  3701. __declspec(thread) HANDLE ProcHandle;
  3702. __declspec(thread) FILE *pstream;
  3703. //+---------------------------------------------------------------------------
  3704. //
  3705. // Function: PipeSpawn (similar to _popen)
  3706. //
  3707. //----------------------------------------------------------------------------
  3708. FILE *
  3709. PipeSpawn (
  3710. const CHAR *cmdstring
  3711. )
  3712. {
  3713. int PipeHandle[2];
  3714. HANDLE WriteHandle, ErrorHandle;
  3715. STARTUPINFO StartupInfo;
  3716. PROCESS_INFORMATION ProcessInformation;
  3717. BOOL Status;
  3718. char CmdLine[1024];
  3719. if (cmdstring == NULL)
  3720. return (NULL);
  3721. // Open the pipe where we'll collect the output.
  3722. _pipe(PipeHandle, 1024, _O_BINARY|_O_NOINHERIT);
  3723. DuplicateHandle(GetCurrentProcess(),
  3724. (HANDLE)_get_osfhandle((LONG)PipeHandle[1]),
  3725. GetCurrentProcess(),
  3726. &WriteHandle,
  3727. 0L,
  3728. TRUE,
  3729. DUPLICATE_SAME_ACCESS);
  3730. DuplicateHandle(GetCurrentProcess(),
  3731. (HANDLE)_get_osfhandle((LONG)PipeHandle[1]),
  3732. GetCurrentProcess(),
  3733. &ErrorHandle,
  3734. 0L,
  3735. TRUE,
  3736. DUPLICATE_SAME_ACCESS);
  3737. _close(PipeHandle[1]);
  3738. pstream = _fdopen(PipeHandle[0], "rb" );
  3739. if (!pstream) {
  3740. CloseHandle(WriteHandle);
  3741. CloseHandle(ErrorHandle);
  3742. _close(PipeHandle[0]);
  3743. return (NULL);
  3744. }
  3745. strcpy(CmdLine, cmdexe);
  3746. strcat(CmdLine, " /c ");
  3747. strcat(CmdLine, cmdstring);
  3748. memset(&StartupInfo, 0, sizeof(STARTUPINFO));
  3749. StartupInfo.cb = sizeof(STARTUPINFO);
  3750. StartupInfo.hStdOutput = WriteHandle;
  3751. StartupInfo.hStdError = ErrorHandle;
  3752. StartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
  3753. StartupInfo.dwFlags = STARTF_USESTDHANDLES;
  3754. memset(&ProcessInformation, 0, sizeof(PROCESS_INFORMATION));
  3755. // And start the process.
  3756. Status = CreateProcess(cmdexe, CmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &StartupInfo, &ProcessInformation);
  3757. CloseHandle(WriteHandle);
  3758. CloseHandle(ErrorHandle);
  3759. CloseHandle(ProcessInformation.hThread);
  3760. if (!Status) {
  3761. fclose(pstream); // This will close the read handle
  3762. pstream = NULL;
  3763. ProcHandle = NULL;
  3764. } else {
  3765. ProcHandle = ProcessInformation.hProcess;
  3766. }
  3767. return (pstream);
  3768. }
  3769. //+---------------------------------------------------------------------------
  3770. //
  3771. // Function: PipeSpawnClose (similar to _pclose)
  3772. //
  3773. //----------------------------------------------------------------------------
  3774. DWORD
  3775. PipeSpawnClose (
  3776. FILE *pstream
  3777. )
  3778. {
  3779. DWORD retval = 0; /* return value (to caller) */
  3780. if ( pstream == NULL) {
  3781. return retval;
  3782. }
  3783. (void)fclose(pstream);
  3784. if ( WaitForSingleObject(ProcHandle, (DWORD) -1L) == 0) {
  3785. GetExitCodeProcess(ProcHandle, &retval);
  3786. }
  3787. CloseHandle(ProcHandle);
  3788. return (retval);
  3789. }