Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3101 lines
85 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_VCTOOL 13
  55. #define STATE_ASN 14
  56. #define STATE_PACKING 15
  57. #define FLAGS_CXX_FILE 0x0001
  58. #define FLAGS_WARNINGS_ARE_ERRORS 0x0002
  59. LPSTR States[] = {
  60. "Unknown", // 0
  61. "Compiling", // 1
  62. "Assembling", // 2
  63. "Building Library", // 3
  64. "Linking Executable", // 4
  65. "Preprocessing", // 5
  66. "Assembling", // 6
  67. "Compiling Precompiled Header", // 7
  68. "Building Type Library", // 8
  69. "Running MIDL on", // 9
  70. "Compiling message file", // 10
  71. "Build Status Line", // 11
  72. "Binplacing", // 12
  73. "Processing", // 13
  74. "Running ASN Compiler on", // 14
  75. "Packing Theme", // 15
  76. };
  77. //----------------------------------------------------------------------------
  78. //
  79. // Function prototypes
  80. //
  81. //----------------------------------------------------------------------------
  82. VOID
  83. GetScreenSize(THREADSTATE *ThreadState);
  84. VOID
  85. GetCursorPosition(USHORT *pRow, USHORT *pCol, USHORT *pRowTop);
  86. VOID
  87. SetCursorPosition(USHORT Row, USHORT Col);
  88. VOID
  89. WriteConsoleCells(
  90. LPSTR String,
  91. USHORT StringLength,
  92. USHORT Row,
  93. USHORT Col,
  94. BYTE *Attribute);
  95. VOID
  96. MoveRectangleUp (
  97. USHORT Top,
  98. USHORT Left,
  99. USHORT Bottom,
  100. USHORT Right,
  101. USHORT NumRow,
  102. BYTE *FillCell);
  103. VOID
  104. ReadConsoleCells(
  105. BYTE *pScreenCell,
  106. USHORT cb,
  107. USHORT Row,
  108. USHORT Column);
  109. VOID
  110. ClearRows(
  111. PTHREADSTATE ThreadState,
  112. USHORT Top,
  113. USHORT NumRows,
  114. PBYTE Cell
  115. );
  116. LPSTR
  117. IsolateFirstToken(
  118. LPSTR *pp,
  119. CHAR delim
  120. );
  121. LPSTR
  122. IsolateLastToken(
  123. LPSTR p,
  124. CHAR delim
  125. );
  126. DWORD
  127. ParallelChildStart(
  128. PPARALLEL_CHILD Data
  129. );
  130. DWORD
  131. PipeSpawnClose (
  132. FILE *pstream
  133. );
  134. FILE *
  135. PipeSpawn (
  136. const CHAR *cmdstring
  137. );
  138. BOOL
  139. DetermineChildState(
  140. PTHREADSTATE ThreadState,
  141. LPSTR p
  142. );
  143. void
  144. PrintChildState(
  145. PTHREADSTATE ThreadState,
  146. LPSTR p,
  147. PFILEREC FileDB
  148. );
  149. //+---------------------------------------------------------------------------
  150. //
  151. // Function: RestoreConsoleMode
  152. //
  153. //----------------------------------------------------------------------------
  154. VOID
  155. RestoreConsoleMode(VOID)
  156. {
  157. SetConsoleMode(GetStdHandle(STD_ERROR_HANDLE), OldConsoleMode);
  158. NewConsoleMode = OldConsoleMode;
  159. }
  160. //+---------------------------------------------------------------------------
  161. //
  162. // Function: IsolateFirstToken
  163. //
  164. // Synopsis: Returns the first token in a string.
  165. //
  166. // Arguments: [pp] -- String to parse
  167. // [delim] -- Token delimiter
  168. //
  169. // Returns: Pointer to first token
  170. //
  171. // Notes: Leading spaces are ignored.
  172. //
  173. //----------------------------------------------------------------------------
  174. LPSTR
  175. IsolateFirstToken(
  176. LPSTR *pp,
  177. CHAR delim
  178. )
  179. {
  180. LPSTR p, Result;
  181. p = *pp;
  182. while (*p <= ' ') {
  183. if (!*p) {
  184. *pp = p;
  185. return( "" );
  186. }
  187. else
  188. p++;
  189. }
  190. Result = p;
  191. while (*p) {
  192. if (*p == delim) {
  193. *p++ = '\0';
  194. break;
  195. }
  196. else {
  197. p++;
  198. }
  199. }
  200. *pp = p;
  201. if (*Result == '.' && Result[1] == '\\') {
  202. return( Result+2 );
  203. }
  204. else {
  205. return( Result );
  206. }
  207. }
  208. //+---------------------------------------------------------------------------
  209. //
  210. // Function: IsolateLastToken
  211. //
  212. // Synopsis: Return the last token in a string.
  213. //
  214. // Arguments: [p] -- String to parse
  215. // [delim] -- Token delimiter
  216. //
  217. // Returns: Pointer to last token
  218. //
  219. // Notes: Trailing spaces are skipped.
  220. //
  221. //----------------------------------------------------------------------------
  222. LPSTR
  223. IsolateLastToken(
  224. LPSTR p,
  225. CHAR delim
  226. )
  227. {
  228. LPSTR Start;
  229. Start = p;
  230. while (*p) {
  231. p++;
  232. }
  233. while (--p > Start) {
  234. if (*p <= ' ') {
  235. *p = '\0';
  236. }
  237. else
  238. break;
  239. }
  240. while (p > Start) {
  241. if (*--p == delim) {
  242. p++;
  243. break;
  244. }
  245. }
  246. if (*p == '.' && p[1] == '\\') {
  247. return( p+2 );
  248. }
  249. else {
  250. return( p );
  251. }
  252. }
  253. //+---------------------------------------------------------------------------
  254. //
  255. // Function: TestPrefix
  256. //
  257. // Synopsis: Returns TRUE if [Prefix] is the first part of [pp]
  258. //
  259. //----------------------------------------------------------------------------
  260. BOOL
  261. TestPrefix(
  262. LPSTR *pp,
  263. LPSTR Prefix
  264. )
  265. {
  266. LPSTR p = *pp;
  267. UINT cb;
  268. if (!_strnicmp( p, Prefix, cb = strlen( Prefix ) )) {
  269. *pp = p + cb;
  270. return( TRUE );
  271. }
  272. else {
  273. return( FALSE );
  274. }
  275. }
  276. //+---------------------------------------------------------------------------
  277. //
  278. // Function: TestPrefixPath
  279. //
  280. // Synopsis: Returns TRUE if [Prefix] is the first part of [pp]
  281. // If the firstpart of [pp] (excluding whitespace) contains
  282. // backslashes, then only the right-most component is used
  283. //
  284. //----------------------------------------------------------------------------
  285. BOOL
  286. TestPrefixPath(
  287. LPSTR *pp,
  288. LPSTR Prefix
  289. )
  290. {
  291. LPSTR p = *pp;
  292. UINT cb;
  293. LPSTR PathString;
  294. INT PathStringLength ;
  295. LPSTR LastComp ;
  296. cb = strlen( Prefix );
  297. if (_strnicmp( p, Prefix, cb ) == 0 ) {
  298. *pp = p + cb;
  299. return( TRUE );
  300. }
  301. else {
  302. PathString = strchr( p, ' ' );
  303. if ( PathString ) {
  304. PathStringLength = (INT) (PathString - p) ;
  305. *PathString = '\0';
  306. LastComp = strrchr( p, '\\' );
  307. *PathString = ' ';
  308. if ( LastComp ) {
  309. if ( _strnicmp( p, Prefix, cb ) == 0 ) {
  310. *pp = p + cb ;
  311. return( TRUE );
  312. }
  313. }
  314. }
  315. return( FALSE );
  316. }
  317. }
  318. //+---------------------------------------------------------------------------
  319. //
  320. // Function: Substr
  321. //
  322. //----------------------------------------------------------------------------
  323. BOOL
  324. Substr(
  325. LPSTR s,
  326. LPSTR p
  327. )
  328. {
  329. LPSTR x;
  330. while (*p) {
  331. x = s;
  332. while (*p++ == *x) {
  333. if (*x == '\0') {
  334. return( TRUE );
  335. }
  336. x++;
  337. }
  338. if (*x == '\0') {
  339. return( TRUE );
  340. }
  341. }
  342. return( FALSE );
  343. }
  344. //+---------------------------------------------------------------------------
  345. //
  346. // Function: WriteTTY
  347. //
  348. // Synopsis: Writes the given string to the output device.
  349. //
  350. // Arguments: [ThreadState] -- Struct containing info about the output dev.
  351. // [p] -- String to display
  352. // [fStatusOutput] -- If TRUE then put on the status line.
  353. //
  354. //----------------------------------------------------------------------------
  355. VOID
  356. WriteTTY (THREADSTATE *ThreadState, LPSTR p, BOOL fStatusOutput)
  357. {
  358. USHORT SaveRow;
  359. USHORT SaveCol;
  360. USHORT SaveRowTop;
  361. USHORT cb, cbT;
  362. PBYTE Attribute;
  363. BOOL ForceNewline;
  364. //
  365. // If we're not writing to the screen then don't do anything fancy, just
  366. // output the string.
  367. //
  368. if (!fStatus || !ThreadState->IsStdErrTty) {
  369. while (TRUE) {
  370. int cch;
  371. cch = strcspn(p, "\r");
  372. if (cch != 0) {
  373. fwrite(p, 1, cch, stderr);
  374. p += cch;
  375. }
  376. if (*p == '\0') {
  377. break;
  378. }
  379. if (p[1] != '\n') {
  380. fwrite(p, 1, 1, stderr);
  381. }
  382. p++;
  383. }
  384. fflush(stderr);
  385. return;
  386. }
  387. assert(ThreadState->cColTotal != 0);
  388. assert(ThreadState->cRowTotal != 0);
  389. //
  390. // Scroll as necessary
  391. //
  392. GetCursorPosition(&SaveRow, &SaveCol, &SaveRowTop);
  393. // During processing, there might be N threads that are displaying
  394. // messages and a single thread displaying directory-level
  395. // linking and building messages. We need to make sure there's room for
  396. // the single thread's message as well as ours. Since that single
  397. // thread displays one line at a time (including CRLF) we must make sure
  398. // that his display (as well as ours) doesn't inadvertantly scroll
  399. // the status line at the top. We do this by guaranteeing that there is
  400. // a blank line at the end.
  401. // We are synchronized with the single top-level thread
  402. // at a higher level than this routine via TTYCriticalSection. We
  403. // are, thus, assured that we control the cursor completely.
  404. // Stay off the LastRow
  405. if (SaveRow == LastRow(ThreadState)) {
  406. USHORT RowTop = 2;
  407. if (fStatus) {
  408. RowTop += SaveRowTop + (USHORT) NumberProcesses + 1;
  409. }
  410. MoveRectangleUp (
  411. RowTop, // Top
  412. 0, // Left
  413. LastRow(ThreadState), // Bottom
  414. LastCol(ThreadState), // Right
  415. 2, // NumRow
  416. ScreenCell); // FillCell
  417. SaveRow -= 2;
  418. SetCursorPosition(SaveRow, SaveCol);
  419. }
  420. //
  421. // Different color for the status line.
  422. //
  423. if (fStatusOutput) {
  424. Attribute = &StatusCell[1];
  425. }
  426. else {
  427. Attribute = &ScreenCell[1];
  428. }
  429. cb = (USHORT) strlen(p);
  430. //
  431. // Write out the string.
  432. //
  433. while (cb > 0) {
  434. ForceNewline = FALSE;
  435. if (cb > 1) {
  436. if (p[cb - 1] == '\n' && p[cb - 2] == '\r') {
  437. cb -= 2;
  438. ForceNewline = TRUE;
  439. }
  440. }
  441. if (cb >= ThreadState->cColTotal - SaveCol) {
  442. cbT = ThreadState->cColTotal - SaveCol;
  443. if (fFullErrors)
  444. ForceNewline = TRUE;
  445. }
  446. else {
  447. cbT = cb;
  448. }
  449. WriteConsoleCells(p, cbT, SaveRow, SaveCol, Attribute);
  450. SetCursorPosition(SaveRow, SaveCol);
  451. if (ForceNewline) {
  452. SaveCol = 0;
  453. SaveRow++;
  454. }
  455. else {
  456. SaveCol += cbT;
  457. }
  458. if (!fFullErrors) {
  459. break;
  460. }
  461. if (cb > cbT) {
  462. // we have more to go... do a newline
  463. // If we're back at the beginning of the bottom line
  464. if (SaveRow == LastRow(ThreadState)) {
  465. USHORT RowTop = 1;
  466. if (fStatus) {
  467. RowTop += SaveRowTop + (USHORT) NumberProcesses + 1;
  468. }
  469. // move window up one line (leaving two lines blank at bottom)
  470. MoveRectangleUp (
  471. RowTop, // Top
  472. 0, // Left
  473. LastRow(ThreadState), // Bottom
  474. LastCol(ThreadState), // Right
  475. 1, // NumRow
  476. ScreenCell); // FillCell
  477. SaveRow--;
  478. }
  479. SetCursorPosition(SaveRow, SaveCol);
  480. }
  481. cb -= cbT;
  482. p += cbT;
  483. }
  484. SetCursorPosition(SaveRow, SaveCol);
  485. }
  486. //+---------------------------------------------------------------------------
  487. //
  488. // Function: WriteTTYLoggingErrors
  489. //
  490. // Synopsis: Writes a message to the appropriate log file and also the
  491. // screen if specified.
  492. //
  493. // Arguments: [Warning] -- TRUE if the message is a warning
  494. // [ThreadState] -- Info about output device
  495. // [p] -- String
  496. //
  497. //----------------------------------------------------------------------------
  498. VOID
  499. WriteTTYLoggingErrors(
  500. BOOL Warning,
  501. PTHREADSTATE ThreadState,
  502. LPSTR p
  503. )
  504. {
  505. UINT cb;
  506. if (fErrorLog) {
  507. cb = strlen( p );
  508. fwrite( p, 1, cb, Warning ? WrnFile : ErrFile );
  509. }
  510. if (fShowWarningsOnScreen && Warning)
  511. {
  512. WriteTTY(ThreadState, p, FALSE);
  513. return;
  514. }
  515. if (!fErrorLog || !Warning) {
  516. WriteTTY(ThreadState, p, FALSE);
  517. }
  518. }
  519. //+---------------------------------------------------------------------------
  520. //
  521. // Function: MsCompilerFilter
  522. //
  523. // Synopsis: Filters output from the compiler so we know what's happening
  524. //
  525. // Arguments: [ThreadState] -- State of thread watching the compiler
  526. // (compiling, linking, etc...)
  527. // [p] -- Message we're trying to parse.
  528. // [FileName] -- [out] Filename in message
  529. // [LineNumber] -- [out] Line number in message
  530. // [Message] -- [out] Message number (for post processing)
  531. // [Warning] -- [out] TRUE if message is a warning.
  532. //
  533. // Returns: TRUE - Message is an error or warning
  534. // FALSE - Message is not an error or a warning
  535. //
  536. // History: 26-Jul-94 LyleC Created
  537. //
  538. // Notes:
  539. //
  540. // This routine filters strings in the MS compiler format. That is:
  541. //
  542. // {toolname} : {number}: {text}
  543. //
  544. // where:
  545. //
  546. // toolname If possible, the container and specific module that has
  547. // the error. For instance, the compiler uses
  548. // filename(linenum), the linker uses library(objname), etc.
  549. // If unable to provide a container, use the tool name.
  550. // number A number, prefixed with some tool identifier (C for
  551. // compiler, LNK for linker, LIB for librarian, N for nmake,
  552. // etc).
  553. // test The descriptive text of the message/error.
  554. //
  555. // Accepted String formats are:
  556. //
  557. // container(module): error/warning NUM ...
  558. // container(module) : error/warning NUM ...
  559. // container (module): error/warning NUM ...
  560. // container (module) : error/warning NUM ...
  561. //
  562. //----------------------------------------------------------------------------
  563. BOOL
  564. MsCompilerFilter(
  565. PTHREADSTATE ThreadState,
  566. LPSTR p,
  567. LPSTR *FileName,
  568. LPSTR *LineNumber,
  569. LPSTR *Message,
  570. BOOL *Warning
  571. )
  572. {
  573. LPSTR p1;
  574. BOOL fCommandLineWarning;
  575. *Message = NULL;
  576. p1 = p;
  577. if (strstr(p, "Compiler error (")) {
  578. *Message = p;
  579. *Warning = FALSE;
  580. if ((p1 = strstr( p, "source=" )))
  581. *LineNumber = p1+7;
  582. else
  583. *LineNumber = "1";
  584. *FileName = ThreadState->ChildCurrentFile;
  585. return TRUE;
  586. }
  587. if (0 == strncmp(p, "fatal error ", strlen("fatal error "))) {
  588. *Message = p;
  589. *Warning = FALSE;
  590. *LineNumber = "1";
  591. *FileName = ThreadState->ChildCurrentFile;
  592. return TRUE;
  593. }
  594. // First look for the " : " or "): " sequence.
  595. while (*p1) {
  596. if ((p1[0] == ')') && (p1[1] == ' ')) p1++;
  597. if ((p1[0] == ' ') || (p1[0] == ')')) {
  598. if (p1[1] == ':') {
  599. if (p1[2] == ' ') {
  600. *Message = p1 + 3;
  601. *p1 = '\0';
  602. break;
  603. }
  604. else
  605. break; // No sense going any further
  606. }
  607. else if ((p1[0] == ' ') && (p1[1] == '('))
  608. p1++;
  609. else
  610. break; // No sense going any further
  611. }
  612. else
  613. p1++;
  614. }
  615. if (*Message != NULL) {
  616. // then figure out if this is an error or warning.
  617. *Warning = TRUE; // Assume the best.
  618. fCommandLineWarning = FALSE;
  619. if (TestPrefix( Message, "error " ) ||
  620. TestPrefix( Message, "fatal error " ) ||
  621. TestPrefix( Message, "command line error " ) ||
  622. TestPrefix( Message, "Compiler error " )) {
  623. *Warning = FALSE;
  624. } else
  625. if (TestPrefix( Message, "warning " )) {
  626. *Warning = TRUE;
  627. } else
  628. if (TestPrefix( Message, "command line warning " )) {
  629. // Command-line warnings don't count when considering whether
  630. // warnings should be errors (under /WX).
  631. *Warning = TRUE;
  632. fCommandLineWarning = TRUE;
  633. }
  634. if (!fCommandLineWarning && (ThreadState->ChildFlags & FLAGS_WARNINGS_ARE_ERRORS) != 0) {
  635. if (Substr( "X0000", *Message )) {
  636. *Warning = TRUE; // Special case this one. Never an error
  637. } else {
  638. *Warning = FALSE; // Warnings treated as errors for this compile
  639. }
  640. }
  641. // Set the container name and look for the module paren's
  642. *FileName = p;
  643. *LineNumber = NULL;
  644. p1 = p;
  645. while (*p1) {
  646. if (*p1 == '(' && p1[1] != ')') {
  647. *p1 = '\0';
  648. p1++;
  649. *LineNumber = p1;
  650. while (*p1) {
  651. if (*p1 == ')') {
  652. *p1 = '\0';
  653. break;
  654. }
  655. p1++;
  656. }
  657. break;
  658. }
  659. p1++;
  660. }
  661. return(TRUE);
  662. }
  663. return(FALSE);
  664. }
  665. //+---------------------------------------------------------------------------
  666. //
  667. // Function: FormatMsErrorMessage
  668. //
  669. // Synopsis: Take the information obtained from MsCompilerFilter,
  670. // reconstruct the error message, and print it to the screen.
  671. //
  672. //----------------------------------------------------------------------------
  673. VOID
  674. FormatMsErrorMessage(
  675. PTHREADSTATE ThreadState,
  676. LPSTR FileName,
  677. LPSTR LineNumber,
  678. LPSTR Message,
  679. BOOL Warning
  680. )
  681. {
  682. char *DirectoryToUse;
  683. if (ThreadState->ChildState == STATE_LIBING) {
  684. if (Warning) {
  685. NumberLibraryWarnings++;
  686. }
  687. else {
  688. NumberLibraryErrors++;
  689. }
  690. }
  691. else
  692. if (ThreadState->ChildState == STATE_LINKING) {
  693. if (Warning) {
  694. NumberLinkWarnings++;
  695. }
  696. else {
  697. NumberLinkErrors++;
  698. }
  699. }
  700. else if (ThreadState->ChildState == STATE_BINPLACE) {
  701. if (Warning) {
  702. NumberBinplaceWarnings++;
  703. }
  704. else {
  705. NumberBinplaceErrors++;
  706. }
  707. }
  708. else {
  709. if (Warning) {
  710. NumberCompileWarnings++;
  711. }
  712. else {
  713. NumberCompileErrors++;
  714. if (ThreadState->CompileDirDB) {
  715. ThreadState->CompileDirDB->DirFlags |= DIRDB_COMPILEERRORS;
  716. }
  717. }
  718. }
  719. if (fParallel && !fNoThreadIndex) {
  720. char buffer[50];
  721. sprintf(buffer, "%d>", ThreadState->ThreadIndex);
  722. WriteTTYLoggingErrors(Warning, ThreadState, buffer);
  723. }
  724. if (FileName) {
  725. DirectoryToUse = ThreadState->ChildCurrentDirectory;
  726. if (TestPrefix( &FileName, CurrentDirectory )) {
  727. DirectoryToUse = CurrentDirectory;
  728. if (*FileName == '\\') {
  729. FileName++;
  730. }
  731. }
  732. if (TestPrefix( &FileName, ThreadState->ChildCurrentDirectory )) {
  733. DirectoryToUse = ThreadState->ChildCurrentDirectory;
  734. if (*FileName == '\\') {
  735. FileName++;
  736. }
  737. }
  738. WriteTTYLoggingErrors( Warning,
  739. ThreadState,
  740. FormatPathName( DirectoryToUse,
  741. FileName
  742. )
  743. );
  744. }
  745. WriteTTYLoggingErrors( Warning, ThreadState, "(" );
  746. if (LineNumber) {
  747. WriteTTYLoggingErrors( Warning, ThreadState, LineNumber );
  748. }
  749. WriteTTYLoggingErrors( Warning, ThreadState, ") : " );
  750. if (Warning) {
  751. WriteTTYLoggingErrors( Warning, ThreadState, "warning " );
  752. }
  753. else {
  754. WriteTTYLoggingErrors( Warning, ThreadState, "error " );
  755. }
  756. WriteTTYLoggingErrors( Warning, ThreadState, Message );
  757. WriteTTYLoggingErrors( Warning, ThreadState, "\r\n" );
  758. }
  759. //+---------------------------------------------------------------------------
  760. //
  761. // Function: PassThrough
  762. //
  763. // Synopsis: Keep track of and print the given message without any
  764. // filtering.
  765. //
  766. // Arguments: [ThreadState] --
  767. // [p] -- Message
  768. // [Warning] -- TRUE if warning
  769. //
  770. // Returns: FALSE
  771. //
  772. //----------------------------------------------------------------------------
  773. BOOL
  774. PassThrough(
  775. PTHREADSTATE ThreadState,
  776. LPSTR p,
  777. BOOL Warning
  778. )
  779. {
  780. if (ThreadState->ChildState == STATE_LIBING) {
  781. if (Warning) {
  782. NumberLibraryWarnings++;
  783. }
  784. else {
  785. NumberLibraryErrors++;
  786. }
  787. }
  788. else
  789. if (ThreadState->ChildState == STATE_LINKING) {
  790. if (Warning) {
  791. NumberLinkWarnings++;
  792. }
  793. else {
  794. NumberLinkErrors++;
  795. }
  796. }
  797. else
  798. if (ThreadState->ChildState == STATE_BINPLACE) {
  799. if (Warning) {
  800. NumberBinplaceWarnings++;
  801. }
  802. else {
  803. NumberBinplaceErrors++;
  804. }
  805. }
  806. else {
  807. if (Warning) {
  808. NumberCompileWarnings++;
  809. }
  810. else {
  811. NumberCompileErrors++;
  812. if (ThreadState->CompileDirDB) {
  813. ThreadState->CompileDirDB->DirFlags |= DIRDB_COMPILEERRORS;
  814. }
  815. }
  816. }
  817. if (fParallel && !fNoThreadIndex) {
  818. char buffer[50];
  819. sprintf(buffer, "%d>", ThreadState->ThreadIndex);
  820. WriteTTYLoggingErrors(Warning, ThreadState, buffer);
  821. }
  822. WriteTTYLoggingErrors( Warning, ThreadState, p );
  823. WriteTTYLoggingErrors( Warning, ThreadState, "\r\n" );
  824. return( FALSE );
  825. }
  826. //+---------------------------------------------------------------------------
  827. //
  828. // Function: PassThroughFilter
  829. //
  830. // Synopsis: Straight pass-through filter for compiler messages
  831. //
  832. //----------------------------------------------------------------------------
  833. BOOL
  834. PassThroughFilter(
  835. PTHREADSTATE ThreadState,
  836. LPSTR p
  837. )
  838. {
  839. return PassThrough( ThreadState, p, FALSE );
  840. }
  841. //+---------------------------------------------------------------------------
  842. //
  843. // Function: C510Filter
  844. //
  845. // Synopsis: Compiler filter which strips out unwanted warnings.
  846. //
  847. // Arguments: [ThreadState] --
  848. // [p] --
  849. //
  850. //----------------------------------------------------------------------------
  851. BOOL
  852. C510Filter(
  853. PTHREADSTATE ThreadState,
  854. LPSTR p
  855. )
  856. {
  857. LPSTR FileName;
  858. LPSTR LineNumber;
  859. LPSTR Message;
  860. BOOL Warning;
  861. LPSTR t;
  862. PFILEREC FileDB;
  863. if (MsCompilerFilter( ThreadState, p,
  864. &FileName,
  865. &LineNumber,
  866. &Message,
  867. &Warning
  868. )
  869. ) {
  870. if (fSilent && Warning) {
  871. if (Substr( "C4001", Message ) ||
  872. Substr( "C4010", Message ) ||
  873. Substr( "C4056", Message ) ||
  874. Substr( "C4061", Message ) ||
  875. Substr( "C4100", Message ) ||
  876. Substr( "C4101", Message ) ||
  877. Substr( "C4102", Message ) ||
  878. Substr( "C4127", Message ) ||
  879. Substr( "C4135", Message ) ||
  880. Substr( "C4201", Message ) ||
  881. Substr( "C4204", Message ) ||
  882. Substr( "C4208", Message ) ||
  883. Substr( "C4509", Message )
  884. ) {
  885. return( FALSE );
  886. }
  887. if (ThreadState->ChildFlags & FLAGS_CXX_FILE) {
  888. if (Substr( "C4047", Message ) ||
  889. Substr( "C4022", Message ) ||
  890. Substr( "C4053", Message )
  891. ) {
  892. return( FALSE );
  893. }
  894. }
  895. }
  896. FormatMsErrorMessage( ThreadState,
  897. FileName, LineNumber, Message, Warning );
  898. return( TRUE );
  899. }
  900. else {
  901. // If we're compiling, then the compiler spits out various bit of info,
  902. // namely:
  903. // 1. filename alone on a line (.c, .cpp, .cxx)
  904. // 2. "Generating Code..." when the back-end is invoked
  905. // 3. "Compiling..." when the front-end is invoked again
  906. if (ThreadState->ChildState == STATE_COMPILING) {
  907. if (0 == strcmp(p, "Generating Code...")) {
  908. strcpy( ThreadState->ChildCurrentFile, "Generating Code..." );
  909. PrintChildState(ThreadState, p, NULL);
  910. return FALSE;
  911. }
  912. t = strrchr(p, '.');
  913. if (t != NULL &&
  914. (0 == strcmp(t, ".cxx") ||
  915. 0 == strcmp(t, ".cpp") ||
  916. 0 == strcmp(t, ".c"))) {
  917. strcpy( ThreadState->ChildCurrentFile, IsolateLastToken(p, ' '));
  918. // strcpy(ThreadState->ChildCurrentFile, p);
  919. if (strstr(ThreadState->ChildCurrentFile, ".cxx") ||
  920. strstr(ThreadState->ChildCurrentFile, ".cpp")) {
  921. ThreadState->ChildFlags |= FLAGS_CXX_FILE;
  922. } else {
  923. ThreadState->ChildFlags &= ~FLAGS_CXX_FILE;
  924. }
  925. FileDB = NULL;
  926. if (ThreadState->CompileDirDB) {
  927. NumberCompiles++;
  928. CopyString( // fixup path string
  929. ThreadState->ChildCurrentFile,
  930. ThreadState->ChildCurrentFile,
  931. TRUE);
  932. if (!fQuicky) {
  933. FileDB = FindSourceFileDB(
  934. ThreadState->CompileDirDB,
  935. ThreadState->ChildCurrentFile,
  936. NULL);
  937. }
  938. }
  939. PrintChildState(ThreadState, p, FileDB);
  940. return FALSE;
  941. }
  942. }
  943. return( FALSE );
  944. }
  945. }
  946. //+---------------------------------------------------------------------------
  947. //
  948. // Function: MSToolFilter
  949. //
  950. //----------------------------------------------------------------------------
  951. BOOL
  952. MSToolFilter(
  953. PTHREADSTATE ThreadState,
  954. LPSTR p
  955. )
  956. {
  957. LPSTR FileName;
  958. LPSTR LineNumber;
  959. LPSTR Message;
  960. BOOL Warning;
  961. if (MsCompilerFilter( ThreadState, p,
  962. &FileName,
  963. &LineNumber,
  964. &Message,
  965. &Warning
  966. )
  967. ) {
  968. FormatMsErrorMessage( ThreadState,
  969. FileName, LineNumber, Message, Warning );
  970. return( TRUE );
  971. }
  972. else {
  973. return( FALSE );
  974. }
  975. }
  976. BOOL
  977. LinkFilter(
  978. PTHREADSTATE ThreadState,
  979. LPSTR p
  980. );
  981. //+---------------------------------------------------------------------------
  982. //
  983. // Function: LinkFilter1
  984. //
  985. //----------------------------------------------------------------------------
  986. BOOL
  987. LinkFilter1(
  988. PTHREADSTATE ThreadState,
  989. LPSTR p
  990. )
  991. {
  992. LPSTR FileName;
  993. LPSTR p1;
  994. char buffer[ 256 ];
  995. if (p[ strlen( p ) - 1 ] == ':') {
  996. return( LinkFilter( ThreadState, p ) );
  997. }
  998. p1 = p;
  999. while (*p1) {
  1000. if (*p1 == '(') {
  1001. *p1++ = 0;
  1002. if (*p1 == '.' && p1[1] == '\\') {
  1003. p1 += 2;
  1004. }
  1005. FileName = p1;
  1006. while (*p1) {
  1007. if (*p1 == ')') {
  1008. *p1++ = 0;
  1009. strcpy( buffer, "L2029: Unresolved external reference to " );
  1010. strcat( buffer, ThreadState->UndefinedId );
  1011. FormatMsErrorMessage( ThreadState, FileName, "1",
  1012. buffer, FALSE
  1013. );
  1014. return( TRUE );
  1015. }
  1016. else {
  1017. p1++;
  1018. }
  1019. }
  1020. }
  1021. else {
  1022. p1++;
  1023. }
  1024. }
  1025. return( FALSE );
  1026. }
  1027. //+---------------------------------------------------------------------------
  1028. //
  1029. // Function: LinkFilter
  1030. //
  1031. //----------------------------------------------------------------------------
  1032. BOOL
  1033. LinkFilter(
  1034. PTHREADSTATE ThreadState,
  1035. LPSTR p
  1036. )
  1037. {
  1038. LPSTR FileName;
  1039. LPSTR LineNumber;
  1040. LPSTR Message;
  1041. BOOL Warning;
  1042. LPSTR p1;
  1043. p1 = p;
  1044. while (*p1) {
  1045. if (*p1 == ':') {
  1046. if (p1[-1] == ']') {
  1047. return( FALSE );
  1048. }
  1049. if (p1[-1] == ' ' && p1[1] == ' ') {
  1050. if (MsCompilerFilter( ThreadState, p,
  1051. &FileName,
  1052. &LineNumber,
  1053. &Message,
  1054. &Warning
  1055. )
  1056. ) {
  1057. if (!Warning || !(_strnicmp(Message, "L4021", 5) ||
  1058. _strnicmp(Message, "L4038", 5) ||
  1059. _strnicmp(Message, "L4046", 5))) {
  1060. if (LineNumber)
  1061. FileName = LineNumber;
  1062. if (FileName[0] == '.' && FileName[1] == '\\') {
  1063. FileName += 2;
  1064. }
  1065. FormatMsErrorMessage( ThreadState, FileName, "1",
  1066. Message, FALSE );
  1067. return( TRUE );
  1068. }
  1069. }
  1070. FormatMsErrorMessage( ThreadState, FileName, "1",
  1071. Message, TRUE );
  1072. return( TRUE );
  1073. }
  1074. if (p1[-1] == ')') {
  1075. p1 -= 11;
  1076. if (p1 > p && !strcmp( p1, " in file(s):" )) {
  1077. strcpy( ThreadState->UndefinedId,
  1078. IsolateFirstToken( &p, ' ' )
  1079. );
  1080. ThreadState->FilterProc = LinkFilter1;
  1081. return( TRUE );
  1082. }
  1083. }
  1084. return( FALSE );
  1085. }
  1086. else {
  1087. p1++;
  1088. }
  1089. }
  1090. return( FALSE );
  1091. }
  1092. //+---------------------------------------------------------------------------
  1093. //
  1094. // Function: CoffFilter
  1095. //
  1096. //----------------------------------------------------------------------------
  1097. BOOL
  1098. CoffFilter(
  1099. PTHREADSTATE ThreadState,
  1100. LPSTR p
  1101. )
  1102. {
  1103. LPSTR FileName;
  1104. LPSTR LineNumber;
  1105. LPSTR Message;
  1106. BOOL Warning;
  1107. if (MsCompilerFilter( ThreadState, p,
  1108. &FileName,
  1109. &LineNumber,
  1110. &Message,
  1111. &Warning
  1112. )
  1113. ) {
  1114. if (fSilent && Warning) {
  1115. if (Substr( "LNK4016", Message )) {
  1116. Warning = FALSE; // undefined turns into an error
  1117. // for builds
  1118. }
  1119. }
  1120. FormatMsErrorMessage( ThreadState,
  1121. FileName, LineNumber, Message, Warning );
  1122. return( TRUE );
  1123. }
  1124. else {
  1125. return( FALSE );
  1126. }
  1127. }
  1128. //+---------------------------------------------------------------------------
  1129. //
  1130. // Function: ClRiscFilter
  1131. //
  1132. // Synopsis: Risc compiler filter
  1133. //
  1134. // Note: It may be possible to remove this filter.
  1135. //
  1136. //----------------------------------------------------------------------------
  1137. BOOL
  1138. ClRiscFilter(
  1139. PTHREADSTATE ThreadState,
  1140. LPSTR p
  1141. )
  1142. {
  1143. LPSTR FileName;
  1144. LPSTR LineNumber;
  1145. LPSTR Message;
  1146. BOOL Warning;
  1147. LPSTR q;
  1148. if (TestPrefix( &p, "cfe: " )) {
  1149. if (strncmp(p, "Error: ", strlen("Error: ")) == 0) {
  1150. p += strlen("Error: ");
  1151. Warning = FALSE;
  1152. } else if (strncmp(p, "Warning: ", strlen("Warning: ")) == 0) {
  1153. p += strlen("Warning: ");
  1154. Warning = TRUE;
  1155. } else {
  1156. return(FALSE);
  1157. }
  1158. q = p;
  1159. if (p = strstr( p, ".\\\\" )) {
  1160. p += 3;
  1161. } else {
  1162. p = q;
  1163. }
  1164. FileName = p;
  1165. while (*p > ' ') {
  1166. if (*p == ',' || (*p == ':' && *(p+1) == ' ')) {
  1167. *p++ = '\0';
  1168. break;
  1169. }
  1170. p++;
  1171. }
  1172. if (*p != ' ') {
  1173. return( FALSE );
  1174. }
  1175. *p++ = '\0';
  1176. if (strcmp(p, "line ") == 0) {
  1177. p += strlen("line ");
  1178. }
  1179. LineNumber = p;
  1180. while (*p != '\0' && *p != ':') {
  1181. p++;
  1182. }
  1183. if (*p != ':') {
  1184. return( FALSE );
  1185. }
  1186. *p++ = '\0';
  1187. if (*p == ' ') {
  1188. Message = p+1;
  1189. ThreadState->LinesToIgnore = 2;
  1190. if (fSilent && Warning) {
  1191. if (!strcmp( Message, "Unknown Control Statement" )
  1192. ) {
  1193. return( FALSE );
  1194. }
  1195. }
  1196. FormatMsErrorMessage( ThreadState,
  1197. FileName,
  1198. LineNumber,
  1199. Message,
  1200. Warning
  1201. );
  1202. return( TRUE );
  1203. }
  1204. }
  1205. //
  1206. // If we did not recognize the cfe compiler, pass it to the MS compiler
  1207. // message filter
  1208. //
  1209. return( C510Filter( ThreadState, p ) );
  1210. }
  1211. //+---------------------------------------------------------------------------
  1212. //
  1213. // Function: MgClientFilter
  1214. //
  1215. //----------------------------------------------------------------------------
  1216. BOOL
  1217. MgClientFilter(
  1218. PTHREADSTATE ThreadState,
  1219. LPSTR p
  1220. )
  1221. {
  1222. return( PassThrough( ThreadState, p, TRUE ) );
  1223. }
  1224. BOOL fAlreadyUnknown = FALSE;
  1225. //+---------------------------------------------------------------------------
  1226. //
  1227. // Function: DetermineChildState
  1228. //
  1229. // Synopsis: Parse the message given by the compiler (or whatever) and try
  1230. // to figure out what it's doing.
  1231. //
  1232. // Arguments: [ThreadState] -- Current thread state
  1233. // [p] -- New message string
  1234. //
  1235. // Returns: TRUE if we figured it out, FALSE if we didn't recognize
  1236. // anything.
  1237. //
  1238. //----------------------------------------------------------------------------
  1239. BOOL
  1240. DetermineChildState(
  1241. PTHREADSTATE ThreadState,
  1242. LPSTR p
  1243. )
  1244. {
  1245. PFILEREC FileDB;
  1246. LPSTR FileName;
  1247. BOOL fPrintChildState = TRUE;
  1248. //
  1249. // ************ Determine what state the child process is in.
  1250. // (Compiling, linking, running MIDL, etc.)
  1251. //
  1252. if ( TestPrefix( &p, "rc ") ) {
  1253. if (*p == ':')
  1254. return FALSE; // This is a warning/error string
  1255. if (strstr( p, "amd64") || strstr( p, "AMD64")) {
  1256. ThreadState->ChildTarget = Amd64TargetMachine.Description;
  1257. }
  1258. else if (strstr( p, "i386") || strstr( p, "I386")) {
  1259. ThreadState->ChildTarget = i386TargetMachine.Description;
  1260. }
  1261. else if (strstr( p, "ia64") || strstr( p, "IA64")) {
  1262. ThreadState->ChildTarget = ia64TargetMachine.Description;
  1263. }
  1264. else {
  1265. ThreadState->ChildTarget = "unknown target";
  1266. }
  1267. ThreadState->FilterProc = MSToolFilter;
  1268. ThreadState->ChildState = STATE_COMPILING;
  1269. ThreadState->ChildFlags = 0;
  1270. strcpy( ThreadState->ChildCurrentFile,
  1271. IsolateLastToken( p, ' ' )
  1272. );
  1273. }
  1274. else
  1275. if (TestPrefix( &p, "rc16 ") ) {
  1276. if (*p == ':')
  1277. return FALSE; // This is a warning/error string
  1278. if (strstr( p, "amd64") || strstr( p, "AMD64")) {
  1279. ThreadState->ChildTarget = Amd64TargetMachine.Description;
  1280. }
  1281. else if (strstr( p, "i386") || strstr( p, "I386")) {
  1282. ThreadState->ChildTarget = i386TargetMachine.Description;
  1283. }
  1284. else if (strstr( p, "ia64") || strstr( p, "IA64")) {
  1285. ThreadState->ChildTarget = ia64TargetMachine.Description;
  1286. }
  1287. else {
  1288. ThreadState->ChildTarget = "unknown target";
  1289. }
  1290. ThreadState->FilterProc = MSToolFilter;
  1291. ThreadState->ChildState = STATE_COMPILING;
  1292. ThreadState->ChildFlags = 0;
  1293. strcpy( ThreadState->ChildCurrentFile,
  1294. IsolateLastToken( p, ' ' )
  1295. );
  1296. }
  1297. else
  1298. if ( TestPrefix( &p, "cl " ) || TestPrefix( &p, "cl386 " ) ) {
  1299. LPSTR pch;
  1300. if (*p == ':')
  1301. return FALSE; // This is a warning/error string
  1302. ThreadState->FilterProc = C510Filter;
  1303. ThreadState->ChildFlags = 0;
  1304. if ( strstr( p, "/WX" ) != NULL || strstr( p, "-WX" ) != NULL) {
  1305. ThreadState->ChildFlags |= FLAGS_WARNINGS_ARE_ERRORS;
  1306. }
  1307. if ((strstr( p, "/EP " ) != NULL) ||
  1308. (strstr( p, "/E " ) != NULL) ||
  1309. (strstr( p, "/P " ) != NULL) ||
  1310. (strstr( p, "-EP " ) != NULL) ||
  1311. (strstr( p, "-E " ) != NULL) ||
  1312. (strstr( p, "-P " ) != NULL)
  1313. ) {
  1314. if (strstr( p, "amd64") || strstr( p, "AMD64")) {
  1315. ThreadState->ChildTarget = Amd64TargetMachine.Description;
  1316. }
  1317. else if (strstr( p, "i386") || strstr( p, "I386")) {
  1318. ThreadState->ChildTarget = i386TargetMachine.Description;
  1319. }
  1320. else if (strstr( p, "ia64") || strstr( p, "IA64")) {
  1321. ThreadState->ChildTarget = ia64TargetMachine.Description;
  1322. }
  1323. else {
  1324. ThreadState->ChildTarget = "unknown target";
  1325. }
  1326. strcpy( ThreadState->ChildCurrentFile,IsolateLastToken( p, ' ' ) );
  1327. if ( strstr( p, ".s" ) != NULL )
  1328. ThreadState->ChildState = STATE_S_PREPROC;
  1329. else
  1330. ThreadState->ChildState = STATE_C_PREPROC;
  1331. }
  1332. else
  1333. if ( (pch = strstr( p, "/Yc" )) != NULL ) {
  1334. size_t namelen = strcspn( pch+3, " \t" );
  1335. if (strstr( p, "ia64") || strstr( p, "IA64")) {
  1336. ThreadState->ChildTarget = ia64TargetMachine.Description;
  1337. } else if (strstr( p, "amd64") || strstr( p, "AMD64")) {
  1338. ThreadState->ChildTarget = Amd64TargetMachine.Description;
  1339. } else {
  1340. ThreadState->ChildTarget = i386TargetMachine.Description;
  1341. }
  1342. ThreadState->ChildState = STATE_PRECOMP;
  1343. strncpy( ThreadState->ChildCurrentFile,
  1344. pch + 3, namelen
  1345. );
  1346. ThreadState->ChildCurrentFile[namelen] = '\0';
  1347. }
  1348. else {
  1349. if (strstr( p, "ia64") || strstr( p, "IA64")) {
  1350. ThreadState->ChildTarget = ia64TargetMachine.Description;
  1351. } else if (strstr( p, "amd64") || strstr( p, "AMD64")) {
  1352. ThreadState->ChildTarget = Amd64TargetMachine.Description;
  1353. } else {
  1354. ThreadState->ChildTarget = i386TargetMachine.Description;
  1355. }
  1356. ThreadState->ChildState = STATE_COMPILING;
  1357. strcpy( ThreadState->ChildCurrentFile, "" );
  1358. fPrintChildState = FALSE;
  1359. }
  1360. }
  1361. else
  1362. if ( TestPrefixPath( &p, "csc " ) || TestPrefixPath( &p, "csc.exe " ) ) {
  1363. ThreadState->ChildState = STATE_COMPILING;
  1364. ThreadState->ChildFlags = 0;
  1365. ThreadState->ChildTarget = "all platforms";
  1366. ThreadState->FilterProc = C510Filter;
  1367. strcpy( ThreadState->ChildCurrentFile,
  1368. IsolateLastToken( p, ' ' )
  1369. );
  1370. }
  1371. else
  1372. if ( TestPrefix( &p, "cl16 " )) {
  1373. if (*p == ':')
  1374. return FALSE; // This is a warning/error string
  1375. ThreadState->FilterProc = C510Filter;
  1376. ThreadState->ChildFlags = 0;
  1377. if (strstr( p, "amd64") || strstr( p, "AMD64")) {
  1378. ThreadState->ChildTarget = Amd64TargetMachine.Description;
  1379. }
  1380. else if (strstr( p, "i386") || strstr( p, "I386")) {
  1381. ThreadState->ChildTarget = i386TargetMachine.Description;
  1382. }
  1383. else if (strstr( p, "ia64") || strstr( p, "IA64")) {
  1384. ThreadState->ChildTarget = ia64TargetMachine.Description;
  1385. }
  1386. else {
  1387. ThreadState->ChildTarget = "unknown target";
  1388. }
  1389. ThreadState->ChildState = STATE_COMPILING;
  1390. strcpy( ThreadState->ChildCurrentFile,
  1391. IsolateLastToken( p, ' ' ));
  1392. }
  1393. else
  1394. if ((TestPrefix( &p, "ml " )) ||
  1395. (TestPrefix( &p, "ml64 " ))) {
  1396. if (*p == ':')
  1397. return FALSE; // This is a warning/error string
  1398. ThreadState->FilterProc = MSToolFilter;
  1399. ThreadState->ChildState = STATE_ASSEMBLING;
  1400. ThreadState->ChildFlags = 0;
  1401. if (strstr( p, "amd64") || strstr( p, "AMD64")) {
  1402. ThreadState->ChildTarget = Amd64TargetMachine.Description;
  1403. }
  1404. else if (strstr( p, "i386") || strstr( p, "I386")) {
  1405. ThreadState->ChildTarget = i386TargetMachine.Description;
  1406. }
  1407. else {
  1408. ThreadState->ChildTarget = "unknown target";
  1409. }
  1410. strcpy( ThreadState->ChildCurrentFile,
  1411. IsolateLastToken( p, ' ' )
  1412. );
  1413. }
  1414. else
  1415. if (TestPrefix( &p, "masm386 ") || TestPrefix( &p, "masm ")) {
  1416. if (*p == ':')
  1417. return FALSE; // This is a warning/error string
  1418. ThreadState->FilterProc = MSToolFilter;
  1419. ThreadState->ChildState = STATE_ASSEMBLING;
  1420. ThreadState->ChildFlags = 0;
  1421. if (strstr( p, "amd64") || strstr( p, "AMD64")) {
  1422. ThreadState->ChildTarget = Amd64TargetMachine.Description;
  1423. }
  1424. else if (strstr( p, "i386") || strstr( p, "I386")) {
  1425. ThreadState->ChildTarget = i386TargetMachine.Description;
  1426. }
  1427. else if (strstr( p, "ia64") || strstr( p, "IA64")) {
  1428. ThreadState->ChildTarget = ia64TargetMachine.Description;
  1429. }
  1430. else {
  1431. ThreadState->ChildTarget = "unknown target";
  1432. }
  1433. if (strstr(p, ",")) {
  1434. strcpy( ThreadState->ChildCurrentFile,
  1435. IsolateLastToken(IsolateFirstToken(&p,','), ' '));
  1436. }
  1437. else {
  1438. strcpy( ThreadState->ChildCurrentFile,
  1439. IsolateLastToken(IsolateFirstToken(&p,';'), ' '));
  1440. }
  1441. }
  1442. else
  1443. if (TestPrefix( &p, "lib " ) ) {
  1444. if (*p == ':')
  1445. return FALSE; // This is a warning/error string
  1446. while (*p == ' ') {
  1447. p++;
  1448. }
  1449. if (strstr( p, "amd64") || strstr( p, "AMD64")) {
  1450. ThreadState->ChildTarget = Amd64TargetMachine.Description;
  1451. }
  1452. else if (strstr( p, "i386") || strstr( p, "I386")) {
  1453. ThreadState->ChildTarget = i386TargetMachine.Description;
  1454. }
  1455. else if (strstr( p, "ia64") || strstr( p, "IA64")) {
  1456. ThreadState->ChildTarget = ia64TargetMachine.Description;
  1457. }
  1458. else {
  1459. ThreadState->ChildTarget = "unknown target";
  1460. }
  1461. ThreadState->FilterProc = CoffFilter;
  1462. ThreadState->ChildFlags = 0;
  1463. if (TestPrefix( &p, "-out:" )) {
  1464. ThreadState->LinesToIgnore = 1;
  1465. ThreadState->ChildState = STATE_LIBING;
  1466. strcpy( ThreadState->ChildCurrentFile,
  1467. IsolateFirstToken( &p, ' ' )
  1468. );
  1469. }
  1470. else
  1471. if (TestPrefix( &p, "-def:" )) {
  1472. ThreadState->LinesToIgnore = 1;
  1473. ThreadState->ChildState = STATE_LIBING;
  1474. strcpy( ThreadState->ChildCurrentFile,
  1475. IsolateFirstToken( &p, ' ' )
  1476. );
  1477. if (TestPrefix( &p, "-out:" )) {
  1478. strcpy( ThreadState->ChildCurrentFile,
  1479. IsolateFirstToken( &p, ' ' )
  1480. );
  1481. }
  1482. }
  1483. else {
  1484. return FALSE;
  1485. }
  1486. }
  1487. else
  1488. if (TestPrefix( &p, "lib16 " ) || TestPrefix( &p, "implib " ) ) {
  1489. if (*p == ':')
  1490. return FALSE; // This is a warning/error string
  1491. while (*p == ' ') {
  1492. p++;
  1493. }
  1494. if (strstr( p, "amd64") || strstr( p, "AMD64")) {
  1495. ThreadState->ChildTarget = Amd64TargetMachine.Description;
  1496. }
  1497. else if (strstr( p, "i386") || strstr( p, "I386")) {
  1498. ThreadState->ChildTarget = i386TargetMachine.Description;
  1499. }
  1500. else if (strstr( p, "ia64") || strstr( p, "IA64")) {
  1501. ThreadState->ChildTarget = ia64TargetMachine.Description;
  1502. }
  1503. else {
  1504. ThreadState->ChildTarget = "unknown target";
  1505. }
  1506. ThreadState->FilterProc = MSToolFilter;
  1507. ThreadState->ChildFlags = 0;
  1508. ThreadState->ChildState = STATE_LIBING;
  1509. if (strstr(p, ";")) {
  1510. strcpy( ThreadState->ChildCurrentFile,
  1511. IsolateFirstToken( &p, ';' ));
  1512. }
  1513. else {
  1514. strcpy( ThreadState->ChildCurrentFile,
  1515. IsolateFirstToken( &p, ' ' ));
  1516. }
  1517. }
  1518. else
  1519. if (TestPrefix( &p, "link " ) ) {
  1520. if (*p == ':')
  1521. return FALSE; // This is a warning/error string
  1522. while (*p == ' ') {
  1523. p++;
  1524. }
  1525. if (strstr( p, "amd64") || strstr( p, "AMD64")) {
  1526. ThreadState->ChildTarget = Amd64TargetMachine.Description;
  1527. }
  1528. else if (strstr( p, "i386") || strstr( p, "I386")) {
  1529. ThreadState->ChildTarget = i386TargetMachine.Description;
  1530. }
  1531. else if (strstr( p, "ia64") || strstr( p, "IA64")) {
  1532. ThreadState->ChildTarget = ia64TargetMachine.Description;
  1533. }
  1534. else {
  1535. ThreadState->ChildTarget = "unknown target";
  1536. }
  1537. ThreadState->FilterProc = CoffFilter;
  1538. ThreadState->ChildFlags = 0;
  1539. if (TestPrefix( &p, "-out:" )) {
  1540. ThreadState->LinesToIgnore = 2;
  1541. ThreadState->ChildState = STATE_LINKING;
  1542. strcpy( ThreadState->ChildCurrentFile,
  1543. IsolateFirstToken( &p, ' ' )
  1544. );
  1545. }
  1546. }
  1547. else
  1548. if (TestPrefix( &p, "link16" ) ) {
  1549. if (*p == ':')
  1550. return FALSE; // This is a warning/error string
  1551. while (*p == ' ') {
  1552. p++;
  1553. }
  1554. if (strstr( p, "amd64") || strstr( p, "AMD64")) {
  1555. ThreadState->ChildTarget = Amd64TargetMachine.Description;
  1556. }
  1557. else if (strstr( p, "i386") || strstr( p, "I386")) {
  1558. ThreadState->ChildTarget = i386TargetMachine.Description;
  1559. }
  1560. else if (strstr( p, "ia64") || strstr( p, "IA64")) {
  1561. ThreadState->ChildTarget = ia64TargetMachine.Description;
  1562. }
  1563. else {
  1564. ThreadState->ChildTarget = "unknown target";
  1565. }
  1566. ThreadState->FilterProc = LinkFilter;
  1567. ThreadState->ChildFlags = 0;
  1568. ThreadState->ChildState = STATE_LINKING;
  1569. p = IsolateLastToken(p, ' ');
  1570. if (strstr(p, ";")) {
  1571. strcpy( ThreadState->ChildCurrentFile,
  1572. IsolateFirstToken( &p, ';' ));
  1573. }
  1574. else {
  1575. strcpy( ThreadState->ChildCurrentFile,
  1576. IsolateFirstToken( &p, ',' ));
  1577. }
  1578. }
  1579. else
  1580. if (TestPrefix( &p, "icl ")) {
  1581. while (*p == ' ') {
  1582. p++;
  1583. }
  1584. ThreadState->ChildState = STATE_COMPILING;
  1585. ThreadState->ChildFlags = 0;
  1586. ThreadState->ChildTarget = ia64TargetMachine.Description;
  1587. ThreadState->FilterProc = C510Filter;
  1588. strcpy( ThreadState->ChildCurrentFile,
  1589. IsolateLastToken( p, ' ' )
  1590. );
  1591. }
  1592. else
  1593. if (TestPrefix( &p, "mktyplib " )) {
  1594. if (*p == ':')
  1595. return FALSE; // This is a warning/error string
  1596. while (*p == ' ') {
  1597. p++;
  1598. }
  1599. ThreadState->ChildState = STATE_MKTYPLIB;
  1600. ThreadState->ChildFlags = 0;
  1601. ThreadState->ChildTarget = "all platforms";
  1602. ThreadState->FilterProc = C510Filter;
  1603. strcpy( ThreadState->ChildCurrentFile,
  1604. IsolateLastToken( p, ' ' )
  1605. );
  1606. }
  1607. else
  1608. if (TestPrefix( &p, "MC: Compiling " )) {
  1609. if (*p == ':')
  1610. return FALSE; // This is a warning/error string
  1611. while (*p == ' ') {
  1612. p++;
  1613. }
  1614. ThreadState->ChildState = STATE_MC;
  1615. ThreadState->ChildFlags = 0;
  1616. ThreadState->ChildTarget = "all platforms";
  1617. ThreadState->FilterProc = C510Filter;
  1618. strcpy( ThreadState->ChildCurrentFile,
  1619. IsolateLastToken( p, ' ' )
  1620. );
  1621. }
  1622. else
  1623. if (TestPrefix( &p, "midl " )) {
  1624. if (*p == ':')
  1625. return FALSE; // This is a warning/error string
  1626. while (*p == ' ') {
  1627. p++;
  1628. }
  1629. ThreadState->ChildState = STATE_MIDL;
  1630. ThreadState->ChildFlags = 0;
  1631. ThreadState->ChildTarget = "all platforms";
  1632. ThreadState->FilterProc = C510Filter;
  1633. strcpy( ThreadState->ChildCurrentFile,
  1634. IsolateLastToken( p, ' ' )
  1635. );
  1636. }
  1637. else
  1638. if (TestPrefix( &p, "asn1 " )) {
  1639. if (*p == ':')
  1640. return FALSE; // This is a warning/error string
  1641. while (*p == ' ') {
  1642. p++;
  1643. }
  1644. ThreadState->ChildState = STATE_ASN;
  1645. ThreadState->ChildFlags = 0;
  1646. ThreadState->ChildTarget = "all platforms";
  1647. ThreadState->FilterProc = C510Filter;
  1648. strcpy(ThreadState->ChildCurrentFile, IsolateLastToken(p, ' '));
  1649. }
  1650. else
  1651. if (TestPrefix( &p, "Build_Status " )) {
  1652. while (*p == ' ') {
  1653. p++;
  1654. }
  1655. ThreadState->ChildState = STATE_STATUS;
  1656. ThreadState->ChildFlags = 0;
  1657. ThreadState->ChildTarget = "";
  1658. ThreadState->FilterProc = C510Filter;
  1659. strcpy( ThreadState->ChildCurrentFile, "" );
  1660. }
  1661. else
  1662. if (TestPrefix( &p, "binplace " )) {
  1663. if (*p == ':')
  1664. return FALSE; // This is a warning/error string
  1665. NumberBinplaces++;
  1666. while (*p == ' ') {
  1667. p++;
  1668. }
  1669. // If this is a standard link/binplace step, don't tell the
  1670. // user what's going on, just pass any errors/warnings to
  1671. // the output. If this is a straight binplace, list the state.
  1672. if (ThreadState->ChildState == STATE_LINKING) {
  1673. ThreadState->ChildState = STATE_BINPLACE;
  1674. ThreadState->ChildFlags = 0;
  1675. ThreadState->FilterProc = MSToolFilter;
  1676. return TRUE;
  1677. } else {
  1678. ThreadState->ChildState = STATE_BINPLACE;
  1679. ThreadState->ChildFlags = 0;
  1680. ThreadState->FilterProc = MSToolFilter;
  1681. strcpy( ThreadState->ChildCurrentFile, IsolateLastToken( p, ' ' ) );
  1682. }
  1683. }
  1684. else
  1685. if (TestPrefix( &p, "cmdcomp " ) ||
  1686. TestPrefix( &p, "cmtempl " ) ||
  1687. TestPrefix( &p, "maptweak ") ||
  1688. TestPrefix( &p, "genord ") ||
  1689. TestPrefix( &p, "makehm ")
  1690. ) {
  1691. if (*p == ':')
  1692. return FALSE; // This is a warning/error string
  1693. while (*p == ' ') {
  1694. p++;
  1695. }
  1696. ThreadState->ChildState = STATE_VCTOOL;
  1697. ThreadState->ChildFlags = 0;
  1698. ThreadState->FilterProc = MSToolFilter;
  1699. strcpy( ThreadState->ChildCurrentFile, IsolateLastToken( p, ' ' ) );
  1700. }
  1701. else
  1702. if ((TestPrefix( &p, "packthem " )) || (TestPrefix( &p, "..\\packthem " )))
  1703. {
  1704. if (*p == ':')
  1705. return FALSE; // This is a warning/error string
  1706. while (*p == ' ')
  1707. p++;
  1708. ThreadState->ChildTarget = i386TargetMachine.Description;
  1709. ThreadState->FilterProc = CoffFilter;
  1710. ThreadState->ChildFlags = 0;
  1711. ThreadState->ChildState = STATE_PACKING;
  1712. if (TestPrefix( &p, "-o" ))
  1713. {
  1714. strcpy( ThreadState->ChildCurrentFile, IsolateFirstToken( &p, ' ' ));
  1715. }
  1716. }
  1717. else {
  1718. return FALSE;
  1719. }
  1720. //
  1721. // ***************** Set the Thread State according to what we determined.
  1722. //
  1723. FileName = ThreadState->ChildCurrentFile;
  1724. if (TestPrefix( &FileName, CurrentDirectory )) {
  1725. if (*FileName == '\\') {
  1726. FileName++;
  1727. }
  1728. if (TestPrefix( &FileName, ThreadState->ChildCurrentDirectory )) {
  1729. if (*FileName == '\\') {
  1730. FileName++;
  1731. }
  1732. }
  1733. strcpy( ThreadState->ChildCurrentFile, FileName );
  1734. }
  1735. FileDB = NULL;
  1736. if (ThreadState->ChildState == STATE_LIBING) {
  1737. NumberLibraries++;
  1738. }
  1739. else
  1740. if (ThreadState->ChildState == STATE_LINKING) {
  1741. NumberLinks++;
  1742. }
  1743. else
  1744. if ((ThreadState->ChildState == STATE_STATUS) ||
  1745. // Don't need to do anything here - binplace count already handled above
  1746. (ThreadState->ChildState == STATE_BINPLACE) ||
  1747. (ThreadState->ChildState == STATE_UNKNOWN)) {
  1748. ; // Do nothing.
  1749. }
  1750. else {
  1751. if (ThreadState->CompileDirDB) {
  1752. NumberCompiles++;
  1753. CopyString( // fixup path string
  1754. ThreadState->ChildCurrentFile,
  1755. ThreadState->ChildCurrentFile,
  1756. TRUE);
  1757. if (!fQuicky) {
  1758. FileDB = FindSourceFileDB(
  1759. ThreadState->CompileDirDB,
  1760. ThreadState->ChildCurrentFile,
  1761. NULL);
  1762. }
  1763. }
  1764. }
  1765. if (strstr(ThreadState->ChildCurrentFile, ".cxx") ||
  1766. strstr(ThreadState->ChildCurrentFile, ".cpp")) {
  1767. ThreadState->ChildFlags |= FLAGS_CXX_FILE;
  1768. }
  1769. if (fPrintChildState)
  1770. PrintChildState(ThreadState, p, FileDB);
  1771. return TRUE;
  1772. }
  1773. //+---------------------------------------------------------------------------
  1774. //
  1775. // Function: PrintChildState
  1776. //
  1777. // Synopsis:
  1778. //
  1779. // Arguments: [ThreadState] -- Current thread state
  1780. //
  1781. // Returns: TRUE if we figured it out, FALSE if we didn't recognize
  1782. // anything.
  1783. //
  1784. //----------------------------------------------------------------------------
  1785. void
  1786. PrintChildState(
  1787. PTHREADSTATE ThreadState,
  1788. LPSTR p,
  1789. PFILEREC FileDB
  1790. )
  1791. {
  1792. USHORT SaveCol;
  1793. USHORT SaveRow;
  1794. USHORT SaveRowTop;
  1795. BOOL fStatusOutput = FALSE;
  1796. char buffer[ DB_MAX_PATH_LENGTH ];
  1797. LONG FilesLeft;
  1798. LONG LinesLeft;
  1799. ULONG LinesPerSecond;
  1800. ULONG SecondsLeft;
  1801. ULONG PercentDone;
  1802. //
  1803. // *********************** Print the thread state to the screen
  1804. //
  1805. if (ThreadState->IsStdErrTty) {
  1806. GetScreenSize(ThreadState);
  1807. assert(ThreadState->cColTotal != 0);
  1808. assert(ThreadState->cRowTotal != 0);
  1809. if (fStatus) {
  1810. GetCursorPosition(&SaveRow, &SaveCol, &SaveRowTop);
  1811. // Clear row for process message
  1812. ClearRows (ThreadState,
  1813. (USHORT) (SaveRowTop + ThreadState->ThreadIndex - 1),
  1814. 1,
  1815. StatusCell);
  1816. // Clear row for status message
  1817. ClearRows (ThreadState,
  1818. (USHORT) (SaveRowTop + NumberProcesses),
  1819. 1,
  1820. StatusCell);
  1821. // Make sure there's still some room at the bottom
  1822. if (SaveRow == LastRow(ThreadState)) {
  1823. USHORT RowTop = 1 + SaveRowTop + (USHORT) NumberProcesses + 1;
  1824. MoveRectangleUp (
  1825. RowTop, // Top
  1826. 0, // Left
  1827. LastRow(ThreadState), // Bottom
  1828. LastCol(ThreadState), // Right
  1829. 1, // NumRow
  1830. ScreenCell); // FillCell
  1831. SaveRow--;
  1832. }
  1833. SetCursorPosition(
  1834. (USHORT) (SaveRowTop + ThreadState->ThreadIndex - 1),
  1835. 0);
  1836. fStatusOutput = TRUE;
  1837. }
  1838. }
  1839. if (szBuildTag) {
  1840. sprintf(buffer, "%s: ", szBuildTag);
  1841. WriteTTY(ThreadState, buffer, fStatusOutput);
  1842. }
  1843. if (fParallel && !fNoThreadIndex) {
  1844. sprintf(buffer, "%d>", ThreadState->ThreadIndex);
  1845. WriteTTY(ThreadState, buffer, fStatusOutput);
  1846. }
  1847. if (ThreadState->ChildState == STATE_UNKNOWN) {
  1848. if (!fAlreadyUnknown) {
  1849. WriteTTY(
  1850. ThreadState,
  1851. "Processing Unknown item(s)...\r\n",
  1852. fStatusOutput);
  1853. fAlreadyUnknown = TRUE;
  1854. }
  1855. }
  1856. else
  1857. if (ThreadState->ChildState == STATE_STATUS) {
  1858. WriteTTY(ThreadState, p, fStatusOutput);
  1859. WriteTTY(ThreadState, "\r\n", fStatusOutput);
  1860. }
  1861. else {
  1862. fAlreadyUnknown = FALSE;
  1863. WriteTTY(ThreadState, States[ThreadState->ChildState], fStatusOutput);
  1864. WriteTTY(ThreadState, " - ", fStatusOutput);
  1865. WriteTTY(
  1866. ThreadState,
  1867. FormatPathName(ThreadState->ChildCurrentDirectory,
  1868. ThreadState->ChildCurrentFile),
  1869. fStatusOutput);
  1870. WriteTTY(ThreadState, " for ", fStatusOutput);
  1871. WriteTTY(ThreadState, ThreadState->ChildTarget, fStatusOutput);
  1872. WriteTTY(ThreadState, "\r\n", fStatusOutput);
  1873. }
  1874. if (StartCompileTime) {
  1875. ElapsedCompileTime += (ULONG)(time(NULL) - StartCompileTime);
  1876. }
  1877. if (FileDB != NULL) {
  1878. StartCompileTime = time(NULL);
  1879. }
  1880. else {
  1881. StartCompileTime = 0L;
  1882. }
  1883. //
  1884. // ****************** Update the status line
  1885. //
  1886. if (fStatus) {
  1887. if (FileDB != NULL) {
  1888. FilesLeft = TotalFilesToCompile - TotalFilesCompiled;
  1889. if (FilesLeft < 0) {
  1890. FilesLeft = 0;
  1891. }
  1892. LinesLeft = TotalLinesToCompile - TotalLinesCompiled;
  1893. if (LinesLeft < 0) {
  1894. LinesLeft = 0;
  1895. PercentDone = 99;
  1896. }
  1897. else if (TotalLinesToCompile != 0) {
  1898. if (TotalLinesCompiled > 20000000L) {
  1899. int TLC = TotalLinesCompiled / 100;
  1900. int TLTC = TotalLinesToCompile / 100;
  1901. PercentDone = (TLC * 100L)/TLTC;
  1902. }
  1903. else
  1904. PercentDone = (TotalLinesCompiled * 100L)/TotalLinesToCompile;
  1905. }
  1906. else {
  1907. PercentDone = 0;
  1908. }
  1909. if (ElapsedCompileTime != 0) {
  1910. LinesPerSecond = TotalLinesCompiled / ElapsedCompileTime;
  1911. }
  1912. else {
  1913. LinesPerSecond = 0;
  1914. }
  1915. if (LinesPerSecond != 0) {
  1916. SecondsLeft = LinesLeft / LinesPerSecond;
  1917. }
  1918. else {
  1919. SecondsLeft = LinesLeft / DEFAULT_LPS;
  1920. }
  1921. sprintf(
  1922. buffer,
  1923. "%2d%% done. %4ld %sLPS Time Left:%s Files: %d %sLines: %s\r\n",
  1924. PercentDone,
  1925. LinesPerSecond,
  1926. fStatusTree? "T" : "",
  1927. FormatTime(SecondsLeft),
  1928. FilesLeft,
  1929. fStatusTree? "Total " : "",
  1930. FormatNumber(LinesLeft));
  1931. SetCursorPosition((USHORT) (SaveRowTop + NumberProcesses), 0);
  1932. WriteTTY(ThreadState, buffer, fStatusOutput);
  1933. }
  1934. if (ThreadState->IsStdErrTty) {
  1935. assert(ThreadState->cColTotal != 0);
  1936. assert(ThreadState->cRowTotal != 0);
  1937. SetCursorPosition(SaveRow, SaveCol);
  1938. }
  1939. }
  1940. //
  1941. // ***************** Keep track of how many files have been compiled.
  1942. //
  1943. if (ThreadState->ChildState == STATE_COMPILING ||
  1944. ThreadState->ChildState == STATE_ASSEMBLING ||
  1945. ThreadState->ChildState == STATE_MKTYPLIB ||
  1946. ThreadState->ChildState == STATE_MIDL ||
  1947. ThreadState->ChildState == STATE_ASN ||
  1948. (FileDB != NULL && ThreadState->ChildState == STATE_PRECOMP)) {
  1949. TotalFilesCompiled++;
  1950. }
  1951. if (FileDB != NULL) {
  1952. TotalLinesCompiled += FileDB->TotalSourceLines;
  1953. }
  1954. }
  1955. //+---------------------------------------------------------------------------
  1956. //
  1957. // Function: ProcessLine
  1958. //
  1959. // Synopsis: Watch the lines coming from the thread for special strings.
  1960. //
  1961. //----------------------------------------------------------------------------
  1962. BOOL
  1963. ProcessLine(
  1964. PTHREADSTATE ThreadState,
  1965. LPSTR p
  1966. )
  1967. {
  1968. LPSTR p1;
  1969. while (*p <= ' ') {
  1970. if (!*p) {
  1971. return( FALSE );
  1972. }
  1973. else {
  1974. p++;
  1975. }
  1976. }
  1977. p1 = p;
  1978. while (*p1) {
  1979. if (*p1 == '\r')
  1980. break;
  1981. else
  1982. p1++;
  1983. }
  1984. *p1 = '\0';
  1985. p1 = p;
  1986. if (TestPrefix( &p1, "Stop." )) {
  1987. return( TRUE );
  1988. }
  1989. // Stop multithread access to shared:
  1990. // database
  1991. // window
  1992. // compilation stats
  1993. EnterCriticalSection(&TTYCriticalSection);
  1994. if (TestPrefix( &p1, "nmake :" )) {
  1995. PassThrough( ThreadState, p, FALSE );
  1996. } else
  1997. if (TestPrefix( &p1, "BUILDMSG: " )) {
  1998. if (TestPrefix(&p1, "Warning")) {
  1999. PassThrough(ThreadState, p, TRUE);
  2000. } else {
  2001. WriteTTY(ThreadState, p, TRUE);
  2002. WriteTTY(ThreadState, "\r\n", TRUE);
  2003. }
  2004. } else
  2005. if (ThreadState->LinesToIgnore) {
  2006. ThreadState->LinesToIgnore--;
  2007. }
  2008. else {
  2009. if ( !DetermineChildState( ThreadState, p ) ) {
  2010. if (ThreadState->FilterProc != NULL) {
  2011. (*ThreadState->FilterProc)( ThreadState, p );
  2012. }
  2013. }
  2014. }
  2015. LeaveCriticalSection(&TTYCriticalSection);
  2016. return( FALSE );
  2017. }
  2018. //+---------------------------------------------------------------------------
  2019. //
  2020. // Function: FilterThread
  2021. //
  2022. // Synopsis: Capture the output of the thread and process it.
  2023. //
  2024. //----------------------------------------------------------------------------
  2025. VOID
  2026. FilterThread(
  2027. PTHREADSTATE ThreadState
  2028. )
  2029. {
  2030. UINT CountBytesRead;
  2031. LPSTR StartPointer = NULL;
  2032. LPSTR EndPointer;
  2033. LPSTR NewPointer;
  2034. ULONG BufSize = 512;
  2035. AllocMem(BufSize, &StartPointer, MT_THREADFILTER);
  2036. while (TRUE) {
  2037. EndPointer = StartPointer;
  2038. do {
  2039. if (BufSize - (EndPointer-StartPointer) < 512) {
  2040. AllocMem(BufSize*2, &NewPointer, MT_THREADFILTER);
  2041. RtlCopyMemory(
  2042. NewPointer,
  2043. StartPointer,
  2044. EndPointer - StartPointer + 1); // copy null byte, too
  2045. EndPointer += NewPointer - StartPointer;
  2046. FreeMem(&StartPointer, MT_THREADFILTER);
  2047. StartPointer = NewPointer;
  2048. BufSize *= 2;
  2049. }
  2050. if (!fgets(EndPointer, 512, ThreadState->ChildOutput)) {
  2051. if (errno != 0)
  2052. BuildError("Pipe read failed - errno = %d\n", errno);
  2053. FreeMem(&StartPointer, MT_THREADFILTER);
  2054. return;
  2055. }
  2056. CountBytesRead = strlen(EndPointer);
  2057. EndPointer = EndPointer + CountBytesRead;
  2058. } while (CountBytesRead == 511 && EndPointer[-1] != '\n');
  2059. CountBytesRead = (UINT)(EndPointer - StartPointer);
  2060. if (LogFile != NULL && CountBytesRead) {
  2061. if (fParallel && !fNoThreadIndex) {
  2062. char buffer[50];
  2063. sprintf(buffer, "%d>", ThreadState->ThreadIndex);
  2064. fwrite(buffer, 1, strlen(buffer), LogFile);
  2065. }
  2066. fwrite(StartPointer, 1, CountBytesRead, LogFile);
  2067. }
  2068. if (ProcessLine(ThreadState, StartPointer)) {
  2069. FreeMem(&StartPointer, MT_THREADFILTER);
  2070. return;
  2071. }
  2072. }
  2073. }
  2074. //+---------------------------------------------------------------------------
  2075. //
  2076. // Function: ExecuteProgram
  2077. //
  2078. // Synopsis: Spawn a new thread to execute the given program and filter
  2079. // its output.
  2080. //
  2081. // Arguments: [ProgramName] --
  2082. // [CommandLine] --
  2083. // [MoreCommandLine] --
  2084. // [MustBeSynchronous] -- For synchronous operation on a
  2085. // multi-processor machine.
  2086. //
  2087. // Returns: ERROR_SUCCESS, ERROR_NOTENOUGHMEMORY, or return code from
  2088. // PipeSpawnClose.
  2089. //
  2090. // Notes: On a multiprocessor machine, this will spawn a new thread
  2091. // and then return, letting the thread run asynchronously. Use
  2092. // WaitForParallelThreads() to ensure all threads are finished.
  2093. // By default, this routine will spawn as many threads as the
  2094. // machine has processors. This can be overridden with the -M
  2095. // option.
  2096. //
  2097. //----------------------------------------------------------------------------
  2098. char ExecuteProgramCmdLine[ 1024 ];
  2099. UINT
  2100. ExecuteProgram(
  2101. LPSTR ProgramName,
  2102. LPSTR CommandLine,
  2103. LPSTR MoreCommandLine,
  2104. BOOL MustBeSynchronous)
  2105. {
  2106. LPSTR p;
  2107. UINT rc;
  2108. THREADSTATE *ThreadState;
  2109. UINT OldErrorMode;
  2110. AllocMem(sizeof(THREADSTATE), &ThreadState, MT_THREADSTATE);
  2111. memset(ThreadState, 0, sizeof(*ThreadState));
  2112. ThreadState->ChildState = STATE_UNKNOWN;
  2113. ThreadState->ChildTarget = "Unknown Target";
  2114. ThreadState->IsStdErrTty = (BOOL) _isatty(_fileno(stderr));
  2115. ThreadState->CompileDirDB = CurrentCompileDirDB;
  2116. if (ThreadState->IsStdErrTty) {
  2117. GetScreenSize(ThreadState);
  2118. assert(ThreadState->cColTotal != 0);
  2119. assert(ThreadState->cRowTotal != 0);
  2120. // We're displaying to the screen, so initialize the console.
  2121. if (!fConsoleInitialized) {
  2122. StatusCell[1] =
  2123. BACKGROUND_RED |
  2124. FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN |
  2125. FOREGROUND_INTENSITY;
  2126. ReadConsoleCells(ScreenCell, sizeof(ScreenCell), 2, 0);
  2127. // If we stumbled upon an old Status line in row 2 of the window,
  2128. // try the current row to avoid using the Status line background
  2129. // colors for fill when scrolling.
  2130. if (ScreenCell[1] == StatusCell[1]) {
  2131. USHORT Row, Col;
  2132. GetCursorPosition(&Row, &Col, NULL);
  2133. ReadConsoleCells(ScreenCell, sizeof(ScreenCell), Row, 0);
  2134. }
  2135. ScreenCell[0] = StatusCell[0] = ' ';
  2136. GetConsoleMode(GetStdHandle(STD_ERROR_HANDLE), &OldConsoleMode);
  2137. NewConsoleMode = OldConsoleMode;
  2138. fConsoleInitialized = TRUE;
  2139. }
  2140. if (fStatus)
  2141. {
  2142. NewConsoleMode = OldConsoleMode & ~(ENABLE_WRAP_AT_EOL_OUTPUT);
  2143. } else
  2144. {
  2145. NewConsoleMode = OldConsoleMode | ENABLE_WRAP_AT_EOL_OUTPUT;
  2146. }
  2147. SetConsoleMode(GetStdHandle(STD_ERROR_HANDLE), NewConsoleMode);
  2148. }
  2149. else {
  2150. ThreadState->cRowTotal = 0;
  2151. ThreadState->cColTotal = 0;
  2152. }
  2153. p = ThreadState->ChildCurrentDirectory;
  2154. GetCurrentDirectory(sizeof(ThreadState->ChildCurrentDirectory), p);
  2155. if (TestPrefix(&p, CurrentDirectory)) {
  2156. if (*p == '\\') {
  2157. p++;
  2158. }
  2159. strcpy(ThreadState->ChildCurrentDirectory, p);
  2160. }
  2161. if (ThreadState->ChildCurrentDirectory[0]) {
  2162. strcat(ThreadState->ChildCurrentDirectory, "\\");
  2163. }
  2164. sprintf(
  2165. ExecuteProgramCmdLine,
  2166. "%s %s%s",
  2167. ProgramName,
  2168. CommandLine,
  2169. MoreCommandLine);
  2170. LogMsg("'%s %s%s'\n", ProgramName, CommandLine, MoreCommandLine);
  2171. if (fParallel && !MustBeSynchronous) {
  2172. PPARALLEL_CHILD ChildData;
  2173. DWORD i;
  2174. DWORD ThreadId;
  2175. AllocMem(sizeof(PARALLEL_CHILD), &ChildData, MT_CHILDDATA);
  2176. strcpy(ChildData->ExecuteProgramCmdLine,ExecuteProgramCmdLine);
  2177. ChildData->ThreadState = ThreadState;
  2178. if (ThreadsStarted < NumberProcesses) {
  2179. if (ThreadsStarted == 0) {
  2180. AllocMem(
  2181. sizeof(HANDLE) * NumberProcesses,
  2182. (VOID **) &WorkerThreads,
  2183. MT_THREADHANDLES);
  2184. AllocMem(
  2185. sizeof(HANDLE) * NumberProcesses,
  2186. (VOID **) &WorkerEvents,
  2187. MT_EVENTHANDLES);
  2188. }
  2189. WorkerEvents[ThreadsStarted] = CreateEvent(NULL,
  2190. FALSE,
  2191. FALSE,
  2192. NULL);
  2193. ChildData->Event = WorkerEvents[ThreadsStarted];
  2194. ThreadState->ThreadIndex = ThreadsStarted+1;
  2195. WorkerThreads[ThreadsStarted] = CreateThread(NULL,
  2196. 0,
  2197. (LPTHREAD_START_ROUTINE)ParallelChildStart,
  2198. ChildData,
  2199. 0,
  2200. &ThreadId);
  2201. if ((WorkerThreads[ThreadsStarted] == NULL) ||
  2202. (WorkerEvents[ThreadsStarted] == NULL)) {
  2203. FreeMem(&ChildData, MT_CHILDDATA);
  2204. FreeMem(&ThreadState, MT_THREADSTATE);
  2205. return(ERROR_NOT_ENOUGH_MEMORY);
  2206. } else {
  2207. WaitForSingleObject(WorkerEvents[ThreadsStarted],INFINITE);
  2208. ++ThreadsStarted;
  2209. }
  2210. } else {
  2211. //
  2212. // Wait for a thread to complete before starting
  2213. // the next one.
  2214. //
  2215. i = WaitForMultipleObjects(NumberProcesses,
  2216. WorkerThreads,
  2217. FALSE,
  2218. INFINITE);
  2219. CloseHandle(WorkerThreads[i]);
  2220. ChildData->Event = WorkerEvents[i];
  2221. ThreadState->ThreadIndex = i+1;
  2222. WorkerThreads[i] = CreateThread(NULL,
  2223. 0,
  2224. (LPTHREAD_START_ROUTINE)ParallelChildStart,
  2225. ChildData,
  2226. 0,
  2227. &ThreadId);
  2228. if (WorkerThreads[i] == NULL) {
  2229. FreeMem(&ChildData, MT_CHILDDATA);
  2230. FreeMem(&ThreadState, MT_THREADSTATE);
  2231. return(ERROR_NOT_ENOUGH_MEMORY);
  2232. } else {
  2233. WaitForSingleObject(WorkerEvents[i],INFINITE);
  2234. }
  2235. }
  2236. return(ERROR_SUCCESS);
  2237. } else {
  2238. //
  2239. // Synchronous operation
  2240. //
  2241. StartCompileTime = 0L;
  2242. ThreadState->ThreadIndex = 1;
  2243. //
  2244. // Disable child error popups in child processes.
  2245. //
  2246. if (fClean) {
  2247. OldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX );
  2248. }
  2249. ThreadState->ChildOutput = PipeSpawn( ExecuteProgramCmdLine );
  2250. if (fClean) {
  2251. SetErrorMode( OldErrorMode );
  2252. }
  2253. rc = ERROR_SUCCESS;
  2254. if (ThreadState->ChildOutput == NULL) {
  2255. BuildError(
  2256. "Exec of '%s' failed - errno = %d\n",
  2257. ExecuteProgramCmdLine,
  2258. errno);
  2259. }
  2260. else {
  2261. FilterThread( ThreadState );
  2262. if (StartCompileTime) {
  2263. ElapsedCompileTime += (ULONG)(time(NULL) - StartCompileTime);
  2264. }
  2265. rc = PipeSpawnClose( ThreadState->ChildOutput );
  2266. if (rc == -1) {
  2267. BuildError("Child Terminate failed - errno = %d\n", errno);
  2268. }
  2269. else
  2270. if (rc) {
  2271. BuildError("%s failed - rc = %d\n", ProgramName, rc);
  2272. }
  2273. }
  2274. if (ThreadState->IsStdErrTty) {
  2275. RestoreConsoleMode();
  2276. }
  2277. FreeMem(&ThreadState, MT_THREADSTATE);
  2278. return( rc );
  2279. }
  2280. }
  2281. //+---------------------------------------------------------------------------
  2282. //
  2283. // Function: WaitForParallelThreads
  2284. //
  2285. // Synopsis: Wait for all threads to finish before returning.
  2286. //
  2287. //----------------------------------------------------------------------------
  2288. VOID
  2289. WaitForParallelThreads(
  2290. VOID
  2291. )
  2292. {
  2293. if (fParallel) {
  2294. WaitForMultipleObjects(ThreadsStarted,
  2295. WorkerThreads,
  2296. TRUE,
  2297. INFINITE);
  2298. while (ThreadsStarted) {
  2299. CloseHandle(WorkerThreads[--ThreadsStarted]);
  2300. CloseHandle(WorkerEvents[ThreadsStarted]);
  2301. }
  2302. if (WorkerThreads != NULL) {
  2303. FreeMem((VOID **) &WorkerThreads, MT_THREADHANDLES);
  2304. FreeMem((VOID **) &WorkerEvents, MT_EVENTHANDLES);
  2305. }
  2306. }
  2307. }
  2308. //+---------------------------------------------------------------------------
  2309. //
  2310. // Function: ParallelChildStart
  2311. //
  2312. // Synopsis: Function that is run once for each thread.
  2313. //
  2314. // Arguments: [Data] -- Data given to CreateThread.
  2315. //
  2316. //----------------------------------------------------------------------------
  2317. DWORD
  2318. ParallelChildStart(
  2319. PPARALLEL_CHILD Data
  2320. )
  2321. {
  2322. UINT OldErrorMode;
  2323. UINT rc;
  2324. //
  2325. // Disable child error popups
  2326. //
  2327. if (fClean) {
  2328. OldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX );
  2329. }
  2330. Data->ThreadState->ChildOutput = PipeSpawn(Data->ExecuteProgramCmdLine);
  2331. if (fClean) {
  2332. SetErrorMode(OldErrorMode);
  2333. }
  2334. //
  2335. // Poke the event to indicate that the child process has
  2336. // started and it is ok for the main thread to change
  2337. // the current directory.
  2338. //
  2339. SetEvent(Data->Event);
  2340. if (Data->ThreadState->ChildOutput==NULL) {
  2341. BuildError(
  2342. "Exec of '%s' failed - errno = %d\n",
  2343. ExecuteProgramCmdLine,
  2344. errno);
  2345. } else {
  2346. FilterThread(Data->ThreadState);
  2347. rc = PipeSpawnClose(Data->ThreadState->ChildOutput);
  2348. if (rc == -1) {
  2349. BuildError("Child terminate failed - errno = %d\n", errno);
  2350. } else {
  2351. if (rc) {
  2352. BuildError("%s failed - rc = %d\n", Data->ExecuteProgramCmdLine, rc);
  2353. }
  2354. }
  2355. }
  2356. if (Data->ThreadState->IsStdErrTty) {
  2357. RestoreConsoleMode();
  2358. }
  2359. FreeMem(&Data->ThreadState, MT_THREADSTATE);
  2360. FreeMem(&Data, MT_CHILDDATA);
  2361. return(rc);
  2362. }
  2363. //+---------------------------------------------------------------------------
  2364. //
  2365. // Function: ClearRows
  2366. //
  2367. //----------------------------------------------------------------------------
  2368. VOID
  2369. ClearRows(
  2370. THREADSTATE *ThreadState,
  2371. USHORT Top,
  2372. USHORT NumRows,
  2373. BYTE *Cell)
  2374. {
  2375. COORD Coord;
  2376. DWORD NumWritten;
  2377. Coord.X = 0;
  2378. Coord.Y = Top;
  2379. FillConsoleOutputCharacter(
  2380. GetStdHandle(STD_ERROR_HANDLE),
  2381. Cell[0],
  2382. ThreadState->cColTotal * NumRows,
  2383. Coord,
  2384. &NumWritten);
  2385. FillConsoleOutputAttribute(
  2386. GetStdHandle(STD_ERROR_HANDLE),
  2387. (WORD) Cell[1],
  2388. ThreadState->cColTotal * NumRows,
  2389. Coord,
  2390. &NumWritten);
  2391. }
  2392. //+---------------------------------------------------------------------------
  2393. //
  2394. // Function: GetScreenSize
  2395. //
  2396. //----------------------------------------------------------------------------
  2397. VOID
  2398. GetScreenSize(THREADSTATE *ThreadState)
  2399. {
  2400. CONSOLE_SCREEN_BUFFER_INFO csbi;
  2401. if (!GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &csbi)) {
  2402. ThreadState->cRowTotal = 25;
  2403. ThreadState->cColTotal = 80;
  2404. }
  2405. else {
  2406. ThreadState->cRowTotal = csbi.srWindow.Bottom + 1;
  2407. ThreadState->cColTotal = csbi.dwSize.X;
  2408. }
  2409. }
  2410. //+---------------------------------------------------------------------------
  2411. //
  2412. // Function: GetCursorPosition
  2413. //
  2414. //----------------------------------------------------------------------------
  2415. VOID
  2416. GetCursorPosition(
  2417. USHORT *pRow,
  2418. USHORT *pCol,
  2419. USHORT *pRowTop)
  2420. {
  2421. CONSOLE_SCREEN_BUFFER_INFO csbi;
  2422. GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &csbi);
  2423. *pRow = csbi.dwCursorPosition.Y;
  2424. *pCol = csbi.dwCursorPosition.X;
  2425. if (pRowTop != NULL) {
  2426. *pRowTop = csbi.srWindow.Top;
  2427. }
  2428. }
  2429. //+---------------------------------------------------------------------------
  2430. //
  2431. // Function: SetCursorPosition
  2432. //
  2433. //----------------------------------------------------------------------------
  2434. VOID
  2435. SetCursorPosition(USHORT Row, USHORT Col)
  2436. {
  2437. COORD Coord;
  2438. Coord.X = Col;
  2439. Coord.Y = Row;
  2440. SetConsoleCursorPosition(GetStdHandle(STD_ERROR_HANDLE), Coord);
  2441. }
  2442. //+---------------------------------------------------------------------------
  2443. //
  2444. // Function: WriteConsoleCells
  2445. //
  2446. //----------------------------------------------------------------------------
  2447. VOID
  2448. WriteConsoleCells(
  2449. LPSTR String,
  2450. USHORT StringLength,
  2451. USHORT Row,
  2452. USHORT Col,
  2453. BYTE *Attribute)
  2454. {
  2455. CONSOLE_SCREEN_BUFFER_INFO csbi;
  2456. DWORD NumWritten;
  2457. WORD OldAttribute;
  2458. COORD StartCoord;
  2459. //
  2460. // Get current default attribute and save it.
  2461. //
  2462. GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &csbi);
  2463. OldAttribute = csbi.wAttributes;
  2464. //
  2465. // Set the default attribute to the passed parameter, along with
  2466. // the cursor position.
  2467. //
  2468. if ((BYTE) OldAttribute != *Attribute) {
  2469. SetConsoleTextAttribute(
  2470. GetStdHandle(STD_ERROR_HANDLE),
  2471. (WORD) *Attribute);
  2472. }
  2473. StartCoord.X = Col;
  2474. StartCoord.Y = Row;
  2475. SetConsoleCursorPosition(GetStdHandle(STD_ERROR_HANDLE), StartCoord);
  2476. //
  2477. // Write the passed string at the current cursor position, using the
  2478. // new default attribute.
  2479. //
  2480. WriteFile(
  2481. GetStdHandle(STD_ERROR_HANDLE),
  2482. String,
  2483. StringLength,
  2484. &NumWritten,
  2485. NULL);
  2486. //
  2487. // Restore previous default attribute.
  2488. //
  2489. if ((BYTE) OldAttribute != *Attribute) {
  2490. SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), OldAttribute);
  2491. }
  2492. }
  2493. //+---------------------------------------------------------------------------
  2494. //
  2495. // Function: MoveRectangleUp
  2496. //
  2497. //----------------------------------------------------------------------------
  2498. VOID
  2499. MoveRectangleUp (
  2500. USHORT Top,
  2501. USHORT Left,
  2502. USHORT Bottom,
  2503. USHORT Right,
  2504. USHORT NumRow,
  2505. BYTE *FillCell)
  2506. {
  2507. SMALL_RECT ScrollRectangle;
  2508. COORD DestinationOrigin;
  2509. CHAR_INFO Fill;
  2510. ScrollRectangle.Left = Left;
  2511. ScrollRectangle.Top = Top;
  2512. ScrollRectangle.Right = Right;
  2513. ScrollRectangle.Bottom = Bottom;
  2514. DestinationOrigin.X = Left;
  2515. DestinationOrigin.Y = Top - NumRow;
  2516. Fill.Char.AsciiChar = FillCell[0];
  2517. Fill.Attributes = (WORD) FillCell[1];
  2518. ScrollConsoleScreenBuffer(
  2519. GetStdHandle(STD_ERROR_HANDLE),
  2520. &ScrollRectangle,
  2521. NULL,
  2522. DestinationOrigin,
  2523. &Fill);
  2524. }
  2525. //+---------------------------------------------------------------------------
  2526. //
  2527. // Function: ReadConsoleCells
  2528. //
  2529. //----------------------------------------------------------------------------
  2530. VOID
  2531. ReadConsoleCells(
  2532. BYTE *ScreenCell,
  2533. USHORT cb,
  2534. USHORT Row,
  2535. USHORT Column)
  2536. {
  2537. COORD BufferSize, BufferCoord;
  2538. SMALL_RECT ReadRegion;
  2539. CHAR_INFO CharInfo[1], *p;
  2540. USHORT CountCells;
  2541. CountCells = cb >> 1;
  2542. assert(CountCells * sizeof(CHAR_INFO) <= sizeof(CharInfo));
  2543. ReadRegion.Top = Row;
  2544. ReadRegion.Left = Column;
  2545. ReadRegion.Bottom = Row;
  2546. ReadRegion.Right = Column + CountCells - 1;
  2547. BufferSize.X = 1;
  2548. BufferSize.Y = CountCells;
  2549. BufferCoord.X = 0;
  2550. BufferCoord.Y = 0;
  2551. ReadConsoleOutput(
  2552. GetStdHandle(STD_ERROR_HANDLE),
  2553. CharInfo,
  2554. BufferSize,
  2555. BufferCoord,
  2556. &ReadRegion);
  2557. p = CharInfo;
  2558. while (CountCells--) {
  2559. *ScreenCell++ = p->Char.AsciiChar;
  2560. *ScreenCell++ = (BYTE) p->Attributes;
  2561. p++;
  2562. }
  2563. }
  2564. //+---------------------------------------------------------------------------
  2565. //
  2566. // Function: ClearLine
  2567. //
  2568. //----------------------------------------------------------------------------
  2569. VOID
  2570. ClearLine(VOID)
  2571. {
  2572. CONSOLE_SCREEN_BUFFER_INFO csbi;
  2573. COORD Coord;
  2574. DWORD NumWritten;
  2575. GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &csbi);
  2576. Coord.Y = csbi.dwCursorPosition.Y;
  2577. Coord.X = csbi.dwCursorPosition.X = 0;
  2578. FillConsoleOutputCharacter(
  2579. GetStdHandle(STD_ERROR_HANDLE),
  2580. ' ',
  2581. csbi.dwSize.X,
  2582. csbi.dwCursorPosition,
  2583. &NumWritten);
  2584. SetConsoleCursorPosition(GetStdHandle(STD_ERROR_HANDLE), Coord);
  2585. fLineCleared = TRUE;
  2586. }
  2587. // PipeSpawn variables. We can get away with one copy per thread.
  2588. __declspec(thread) HANDLE ProcHandle;
  2589. __declspec(thread) FILE *pstream;
  2590. //+---------------------------------------------------------------------------
  2591. //
  2592. // Function: PipeSpawn (similar to _popen)
  2593. //
  2594. //----------------------------------------------------------------------------
  2595. FILE *
  2596. PipeSpawn (
  2597. const CHAR *cmdstring
  2598. )
  2599. {
  2600. int PipeHandle[2];
  2601. HANDLE WriteHandle, ErrorHandle;
  2602. STARTUPINFO StartupInfo;
  2603. PROCESS_INFORMATION ProcessInformation;
  2604. BOOL Status;
  2605. char CmdLine[1024];
  2606. if (cmdstring == NULL)
  2607. return (NULL);
  2608. // Open the pipe where we'll collect the output.
  2609. _pipe(PipeHandle, 1024, _O_BINARY|_O_NOINHERIT);
  2610. DuplicateHandle(GetCurrentProcess(),
  2611. (HANDLE)_get_osfhandle((LONG)PipeHandle[1]),
  2612. GetCurrentProcess(),
  2613. &WriteHandle,
  2614. 0L,
  2615. TRUE,
  2616. DUPLICATE_SAME_ACCESS);
  2617. DuplicateHandle(GetCurrentProcess(),
  2618. (HANDLE)_get_osfhandle((LONG)PipeHandle[1]),
  2619. GetCurrentProcess(),
  2620. &ErrorHandle,
  2621. 0L,
  2622. TRUE,
  2623. DUPLICATE_SAME_ACCESS);
  2624. _close(PipeHandle[1]);
  2625. pstream = _fdopen(PipeHandle[0], "rb" );
  2626. if (!pstream) {
  2627. CloseHandle(WriteHandle);
  2628. CloseHandle(ErrorHandle);
  2629. _close(PipeHandle[0]);
  2630. return(NULL);
  2631. }
  2632. strcpy(CmdLine, cmdexe);
  2633. strcat(CmdLine, " /c ");
  2634. strcat(CmdLine, cmdstring);
  2635. memset(&StartupInfo, 0, sizeof(STARTUPINFO));
  2636. StartupInfo.cb = sizeof(STARTUPINFO);
  2637. StartupInfo.hStdOutput = WriteHandle;
  2638. StartupInfo.hStdError = ErrorHandle;
  2639. StartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
  2640. StartupInfo.dwFlags = STARTF_USESTDHANDLES;
  2641. memset(&ProcessInformation, 0, sizeof(PROCESS_INFORMATION));
  2642. // And start the process.
  2643. Status = CreateProcess(cmdexe, CmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &StartupInfo, &ProcessInformation);
  2644. CloseHandle(WriteHandle);
  2645. CloseHandle(ErrorHandle);
  2646. CloseHandle(ProcessInformation.hThread);
  2647. if (!Status) {
  2648. fclose(pstream); // This will close the read handle
  2649. pstream = NULL;
  2650. ProcHandle = NULL;
  2651. } else {
  2652. ProcHandle = ProcessInformation.hProcess;
  2653. }
  2654. return(pstream);
  2655. }
  2656. //+---------------------------------------------------------------------------
  2657. //
  2658. // Function: PipeSpawnClose (similar to _pclose)
  2659. //
  2660. //----------------------------------------------------------------------------
  2661. DWORD
  2662. PipeSpawnClose (
  2663. FILE *pstream
  2664. )
  2665. {
  2666. DWORD retval = 0; /* return value (to caller) */
  2667. if ( pstream == NULL) {
  2668. return retval;
  2669. }
  2670. (void)fclose(pstream);
  2671. if ( WaitForSingleObject(ProcHandle, (DWORD) -1L) == 0) {
  2672. GetExitCodeProcess(ProcHandle, &retval);
  2673. }
  2674. CloseHandle(ProcHandle);
  2675. return(retval);
  2676. }