Author: hyperion
Date: Mon Jun 1 19:17:41 2009
New Revision: 41235
URL:
http://svn.reactos.org/svn/reactos?rev=41235&view=rev
Log:
added tools/msc_helper
added tools/msc_helper/msc_helper.cpp
added tools/msc_helper/msc_helper.rbuild
Build tool to invoke Microsoft tools, overriding the %PATH% variable and optionally
filtering out the name of the file being compiled
Will be used by the Visual C++ support for rbuild
Added:
trunk/reactos/tools/msc_helper/ (with props)
trunk/reactos/tools/msc_helper/msc_helper.cpp (with props)
trunk/reactos/tools/msc_helper/msc_helper.rbuild (with props)
Propchange: trunk/reactos/tools/msc_helper/
------------------------------------------------------------------------------
--- bugtraq:logregex (added)
+++ bugtraq:logregex Mon Jun 1 19:17:41 2009
@@ -1,0 +1,2 @@
+([Ii]ssue|[Bb]ug)s? #?(\d+)(,? ?#?(\d+))*(,? ?(and |or )?#?(\d+))?
+(\d+)
Propchange: trunk/reactos/tools/msc_helper/
------------------------------------------------------------------------------
bugtraq:message = See issue #%BUGID% for more details.
Propchange: trunk/reactos/tools/msc_helper/
------------------------------------------------------------------------------
bugtraq:url =
http://www.reactos.org/bugzilla/show_bug.cgi?id=%BUGID%
Propchange: trunk/reactos/tools/msc_helper/
------------------------------------------------------------------------------
tsvn:logminsize = 10
Added: trunk/reactos/tools/msc_helper/msc_helper.cpp
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/tools/msc_helper/msc_helpe…
==============================================================================
--- trunk/reactos/tools/msc_helper/msc_helper.cpp (added)
+++ trunk/reactos/tools/msc_helper/msc_helper.cpp [iso-8859-1] Mon Jun 1 19:17:41 2009
@@ -1,0 +1,475 @@
+/*
+ Copyright (c) 2009 KJK::Hyperion
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#include <functional>
+#include <iterator>
+
+#include <tchar.h>
+#include <limits.h>
+
+#include <stdio.h>
+
+#define WIN32_LEAN_AND_MEAN
+#define STRICT
+#include <windows.h>
+
+#undef RtlMoveMemory
+extern "C" DECLSPEC_IMPORT void NTAPI RtlMoveMemory(void UNALIGNED *, const
void UNALIGNED *, SIZE_T);
+
+#ifndef ARRAYSIZE
+#define ARRAYSIZE(X_) (sizeof(X_) / sizeof((X_)[0]))
+#endif
+
+#include <kjk/argv_parser.h>
+#include <kjk/stringz_iterator.h>
+
+using namespace kjk;
+
+namespace
+{
+ bool WriteAll(HANDLE hFile, const void * p, size_t cb)
+ {
+ const char * pb = static_cast<const char *>(p);
+ bool ret = cb == 0;
+
+ while(cb)
+ {
+ DWORD cbToWrite;
+
+ if(cb > MAXLONG)
+ cbToWrite = MAXLONG;
+ else
+ cbToWrite = static_cast<DWORD>(cb);
+
+ DWORD cbWritten;
+ ret = !!WriteFile(hFile, pb, cbToWrite, &cbWritten, NULL);
+
+ if(!ret)
+ break;
+
+ cb -= cbWritten;
+ pb += cbWritten;
+ }
+
+ return ret;
+ }
+
+ DECLSPEC_NORETURN
+ void Exit(DWORD dwExitCode)
+ {
+ for(;;) TerminateProcess(GetCurrentProcess(), dwExitCode);
+ }
+
+ DECLSPEC_NORETURN
+ void Die(DWORD dwExitCode, const char * pszFunction, DWORD dwErrCode)
+ {
+ DWORD_PTR args[] = { (DWORD_PTR)pszFunction, dwErrCode };
+
+ char * pszMessage;
+ DWORD cchMessage = FormatMessageA
+ (
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY |
FORMAT_MESSAGE_FROM_STRING,
+ "msc_helper: %1!s!() failed: error %2!lu!\n",
+ 0,
+ 0,
+ (LPSTR)&pszMessage,
+ 0,
+ (va_list *)args
+ );
+
+ if(cchMessage)
+ {
+ (void)WriteAll(GetStdHandle(STD_ERROR_HANDLE), pszMessage, cchMessage);
+ LocalFree((HLOCAL)pszMessage);
+ }
+
+ Exit(dwExitCode);
+ }
+
+ DECLSPEC_NORETURN
+ void Die(const char * pszFunction)
+ {
+ Die(1, pszFunction, GetLastError());
+ }
+
+ DECLSPEC_NORETURN
+ void Die(const char * pszFunction, DWORD dwExitCode)
+ {
+ Die(1, pszFunction, dwExitCode);
+ }
+
+ template<size_t N>
+ DECLSPEC_NORETURN
+ void DieMessage(const char (& msg)[N])
+ {
+ (void)WriteAll(GetStdHandle(STD_ERROR_HANDLE), msg, (N) - 1);
+ Exit(1);
+ }
+
+ DECLSPEC_NORETURN
+ void OutOfMemory()
+ {
+ DieMessage("msc_helper: out of memory\n");
+ }
+
+ class store_argument
+ {
+ private:
+ char * m_arg;
+ size_t m_argLen;
+
+ public:
+ // Pretend we are an STL container
+ typedef TCHAR value_type;
+ typedef TCHAR * pointer;
+ typedef TCHAR& reference;
+ typedef const TCHAR * const_pointer;
+ typedef const TCHAR& const_reference;
+
+ void push_back(TCHAR x)
+ {
+#ifdef UNICODE
+ if(x > CHAR_MAX)
+ DieMessage("msc_helper: invalid character in command line\n");
+#endif
+ m_arg = static_cast<char *>(HeapReAlloc(GetProcessHeap(), 0, m_arg, m_argLen +
1));
+
+ if(m_arg == NULL)
+ OutOfMemory();
+
+ m_arg[m_argLen] = static_cast<char>(x);
+ ++ m_argLen;
+ }
+
+ public:
+ store_argument(): m_arg(static_cast<char *>(HeapAlloc(GetProcessHeap(), 0, 1))),
m_argLen(0)
+ {
+ if(m_arg == NULL)
+ OutOfMemory();
+ }
+
+ const char * get_arg() const { return m_arg; }
+ size_t get_arg_len() const { return m_argLen; }
+ };
+
+ class filter_output
+ {
+ private:
+ const char * m_pFilterLine;
+ size_t m_cbFilterLine;
+ HANDLE m_hOutput;
+ bool& m_fDone;
+
+ static DWORD s_cbDummy;
+ static DWORD s_pipeId;
+
+ char m_buffer[1024];
+ LPTSTR m_pszPipeName;
+ HANDLE m_hReadFrom;
+ OVERLAPPED m_asyncRead;
+ char * m_pLineBuffer;
+ size_t m_cbLineBuffer;
+
+ bool begin_read()
+ {
+ bool bRet = !!ReadFile(m_hReadFrom, m_buffer, sizeof(m_buffer), &s_cbDummy,
&m_asyncRead);
+
+ if(!bRet)
+ {
+ bRet = GetLastError() != ERROR_BROKEN_PIPE;
+
+ if(bRet)
+ {
+ bRet = GetLastError() == ERROR_IO_PENDING;
+
+ if(!bRet)
+ Die("ReadFile");
+ }
+ }
+
+ return bRet;
+ }
+
+ void push_input(size_t cbBufferValid)
+ {
+ if(m_fDone)
+ {
+ if(!WriteAll(m_hOutput, m_buffer, cbBufferValid))
+ Die("WriteFile");
+
+ return;
+ }
+
+ // Add the data read from output to the line buffer
+ size_t cbLineBufferNew = m_cbLineBuffer + cbBufferValid;
+
+ if(m_pLineBuffer)
+ m_pLineBuffer = static_cast<char *>(HeapReAlloc(GetProcessHeap(), 0,
m_pLineBuffer, cbLineBufferNew));
+ else
+ m_pLineBuffer = static_cast<char *>(HeapAlloc(GetProcessHeap(), 0,
cbLineBufferNew));
+
+ if(m_pLineBuffer == NULL)
+ OutOfMemory();
+
+ RtlMoveMemory(m_pLineBuffer + m_cbLineBuffer, m_buffer, cbBufferValid);
+
+ // Parse all complete lines in the line buffer
+ size_t cbLineStart = 0;
+
+ for(size_t i = m_cbLineBuffer; i < cbLineBufferNew; ++ i)
+ {
+ // We have a complete line
+ if(m_pLineBuffer[i] == '\n' || m_pLineBuffer[i] == '\r')
+ {
+ size_t cbLine = i - cbLineStart;
+
+ ++ i;
+
+ if(i < cbLineBufferNew && m_pLineBuffer[i - 1] == '\r' &&
m_pLineBuffer[i] == '\n')
+ ++ i;
+
+ size_t cbLineFull = i - cbLineStart;
+
+ bool fMatched = cbLine == m_cbFilterLine && memcmp(m_pLineBuffer +
cbLineStart, m_pFilterLine, m_cbFilterLine) == 0;
+
+ // The line doesn't match: dump it
+ if(!fMatched)
+ {
+ if(!WriteAll(m_hOutput, m_pLineBuffer + cbLineStart, cbLineFull))
+ Die("WriteFile");
+ }
+ // The line matches: we are done
+ else
+ m_fDone = fMatched;
+
+ cbLineStart = i;
+ }
+
+ // Filtering is complete: from now on, just dump everything
+ if(m_fDone)
+ {
+ if(!WriteAll(m_hOutput, m_buffer + i, cbLineBufferNew - i))
+ Die("WriteFile");
+
+ HeapFree(GetProcessHeap(), 0, m_pLineBuffer);
+ return;
+ }
+ }
+
+ // Re-buffer what's left
+ m_cbLineBuffer = cbLineBufferNew - cbLineStart;
+ RtlMoveMemory(m_pLineBuffer, m_pLineBuffer + cbLineStart, m_cbLineBuffer);
+ }
+
+ public:
+ filter_output(const char * pFilterLine, size_t cbFilterLine, HANDLE hOutput, bool *
pfDone):
+ m_pFilterLine(pFilterLine),
+ m_cbFilterLine(cbFilterLine),
+ m_hOutput(hOutput),
+ m_fDone(*pfDone),
+ m_asyncRead(),
+ m_pLineBuffer(0),
+ m_cbLineBuffer(0)
+ {
+ for(;;)
+ {
+ DWORD_PTR args[] = { GetCurrentProcessId(), s_pipeId };
+
+ DWORD cchPipeName = FormatMessage
+ (
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY |
FORMAT_MESSAGE_FROM_STRING,
+ TEXT("\\\\.\\pipe\\msc_helper-%1!08X!-%2!08X!"),
+ 0,
+ 0,
+ (LPTSTR)&m_pszPipeName,
+ 0,
+ (va_list *)args
+ );
+
+ if(cchPipeName == 0)
+ Die("FormatMessage");
+
+ m_hReadFrom = CreateNamedPipe(m_pszPipeName, PIPE_ACCESS_INBOUND |
FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE, 1, 0, 0, 0, NULL);
+
+ ++ s_pipeId;
+
+ if(m_hReadFrom != INVALID_HANDLE_VALUE)
+ break;
+
+ if(GetLastError() != ERROR_PIPE_BUSY)
+ Die("CreateNamedPipe");
+ }
+
+ // Just in case
+ bool fEmptyFilter = m_cbFilterLine == 0;
+
+ if(fEmptyFilter)
+ m_fDone = fEmptyFilter;
+ }
+
+ HANDLE open_write_end(LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD
dwFlagsAndAttributes, HANDLE hTemplateFile)
+ {
+ HANDLE hWritePipe = CreateFile(m_pszPipeName, GENERIC_WRITE, FILE_SHARE_READ,
lpSecurityAttributes, OPEN_EXISTING, dwFlagsAndAttributes, hTemplateFile);
+
+ if(hWritePipe == INVALID_HANDLE_VALUE)
+ Die("CreateFile");
+
+ (void)begin_read();
+ return hWritePipe;
+ }
+
+ HANDLE get_read_completion() const
+ {
+ return m_hReadFrom;
+ }
+
+ bool operator()()
+ {
+ DWORD cbBufferValid;
+
+ if(!GetOverlappedResult(m_hReadFrom, &m_asyncRead, &cbBufferValid, TRUE))
+ {
+ bool b = GetLastError() != ERROR_BROKEN_PIPE;
+
+ if(!b)
+ return b;
+
+ Die("ReadFile");
+ }
+
+ push_input(cbBufferValid);
+ return begin_read();
+ }
+ };
+
+ DWORD filter_output::s_cbDummy = 0;
+ DWORD filter_output::s_pipeId = 0;
+}
+
+int main()
+{
+ DWORD dwExitCode = 1;
+
+ // Parse the command line
+ LPCTSTR pszCommandLine = GetCommandLine();
+
+ // Skip argv[0]
+ pszCommandLine = skip_argument(stringz_begin(pszCommandLine),
stringz_end(pszCommandLine)).base();
+
+ // Get argv[1]: the line that should be filtered out of the output
+ // argv[2..N] will become argv[0..N-2] of the compiler
+ store_argument filterLine;
+ pszCommandLine = copy_argument(stringz_begin(pszCommandLine),
stringz_end(pszCommandLine), std::back_inserter(filterLine)).base();
+
+ // Initialize the output filters
+ bool fDone = false;
+ filter_output filterStdOutput(filterLine.get_arg(), filterLine.get_arg_len(),
GetStdHandle(STD_OUTPUT_HANDLE), &fDone);
+ filter_output filterStdError(filterLine.get_arg(), filterLine.get_arg_len(),
GetStdHandle(STD_ERROR_HANDLE), &fDone);
+
+ // A handle that will never be signaled
+ HANDLE hNever;
+
+ if(!DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(),
&hNever, SYNCHRONIZE, FALSE, 0))
+ Die("DuplicateHandle");
+
+ // Fix the environment
+ static TCHAR szPath[32768];
+ DWORD cchPath = GetEnvironmentVariable(TEXT("MSC_HELPER_PATH"), szPath,
ARRAYSIZE(szPath));
+
+ if(cchPath > ARRAYSIZE(szPath))
+ DieMessage("msc_helper: %MSC_HELPER_PATH% variable too big\n");
+
+ if(cchPath > 0 && !SetEnvironmentVariable(TEXT("PATH"), szPath))
+ Die("SetEnvironmentVariable");
+
+ // Run the sub-process
+ STARTUPINFO si;
+ GetStartupInfo(&si);
+
+ si.dwFlags |= STARTF_USESTDHANDLES;
+
+ si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+
+ SECURITY_ATTRIBUTES pipeAttributes = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
+ si.hStdOutput = filterStdOutput.open_write_end(&pipeAttributes, 0, NULL);
+ si.hStdError = filterStdError.open_write_end(&pipeAttributes, 0, NULL);
+
+ PROCESS_INFORMATION pi = {};
+
+ if(!CreateProcess(NULL, const_cast<LPTSTR>(pszCommandLine), NULL, NULL, TRUE, 0,
NULL, NULL, &si, &pi))
+ Die("CreateProcess");
+
+ CloseHandle(pi.hThread);
+ CloseHandle(si.hStdOutput);
+ CloseHandle(si.hStdError);
+
+ (void)SetProcessWorkingSetSize(GetCurrentProcess(), (SIZE_T)-1, (SIZE_T)-1);
+
+ HANDLE waitHandles[3] =
+ {
+ pi.hProcess,
+ filterStdOutput.get_read_completion(),
+ filterStdError.get_read_completion()
+ };
+
+ unsigned done = 0;
+
+ char * pLineBuffer = NULL;
+ size_t cbLineBuffer = 0;
+
+ while(done < ARRAYSIZE(waitHandles))
+ {
+ switch(WaitForMultipleObjects(ARRAYSIZE(waitHandles), waitHandles, FALSE, INFINITE))
+ {
+ case WAIT_OBJECT_0:
+ GetExitCodeProcess(pi.hProcess, &dwExitCode);
+ waitHandles[WAIT_OBJECT_0] = hNever;
+ ++ done;
+ break;
+
+ case WAIT_OBJECT_0 + 1:
+ if(!filterStdOutput())
+ {
+ waitHandles[WAIT_OBJECT_0 + 1] = hNever;
+ ++ done;
+ }
+
+ break;
+
+ case WAIT_OBJECT_0 + 2:
+ if(!filterStdError())
+ {
+ waitHandles[WAIT_OBJECT_0 + 2] = hNever;
+ ++ done;
+ }
+
+ break;
+
+ default:
+ Die("WaitForMultipleObjects");
+ }
+ }
+
+ Exit(dwExitCode);
+}
+
+// EOF
Propchange: trunk/reactos/tools/msc_helper/msc_helper.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/reactos/tools/msc_helper/msc_helper.rbuild
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/tools/msc_helper/msc_helpe…
==============================================================================
--- trunk/reactos/tools/msc_helper/msc_helper.rbuild (added)
+++ trunk/reactos/tools/msc_helper/msc_helper.rbuild [iso-8859-1] Mon Jun 1 19:17:41
2009
@@ -1,0 +1,6 @@
+<?xml version="1.0"?>
+<module name="msc_helper" type="buildtool">
+ <define name="UNICODE" />
+ <define name="_UNICODE" />
+ <file>msc_helper.cpp</file>
+</module>
Propchange: trunk/reactos/tools/msc_helper/msc_helper.rbuild
------------------------------------------------------------------------------
svn:eol-style = native