295 lines
8 KiB
C++
295 lines
8 KiB
C++
|
// gc.cpp : Defines the entry point for the console application.
|
||
|
//
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
#include "AssertWithStack.cpp"
|
||
|
|
||
|
CSpUnicodeSupport g_Unicode;
|
||
|
|
||
|
class CError : public ISpErrorLog
|
||
|
{
|
||
|
public:
|
||
|
CError(const WCHAR * pszFileName)
|
||
|
{
|
||
|
m_pszFileName = pszFileName;
|
||
|
}
|
||
|
STDMETHODIMP QueryInterface(REFIID riid, void ** ppv)
|
||
|
{
|
||
|
if (riid == __uuidof(IUnknown) ||
|
||
|
riid == __uuidof(ISpErrorLog))
|
||
|
{
|
||
|
*ppv = (ISpErrorLog *)this;
|
||
|
return S_OK;
|
||
|
}
|
||
|
*ppv = NULL;
|
||
|
return E_NOINTERFACE;
|
||
|
}
|
||
|
STDMETHODIMP_(ULONG) AddRef()
|
||
|
{
|
||
|
return 2;
|
||
|
}
|
||
|
STDMETHODIMP_(ULONG) Release()
|
||
|
{
|
||
|
return 1;
|
||
|
}
|
||
|
// -- ISpErrorLog
|
||
|
STDMETHODIMP AddError(const long lLine, HRESULT hr, const WCHAR * pszDescription, const WCHAR * pszHelpFile, DWORD dwHelpContext);
|
||
|
|
||
|
// --- data members
|
||
|
const WCHAR * m_pszFileName;
|
||
|
};
|
||
|
|
||
|
HRESULT CError::AddError(const long lLine, HRESULT hr, const WCHAR * pszDescription, const WCHAR * pszHelpFile, DWORD dwHelpContext)
|
||
|
{
|
||
|
SPDBG_FUNC("CError::AddError");
|
||
|
USES_CONVERSION;
|
||
|
if (lLine > 0)
|
||
|
{
|
||
|
fprintf(stderr, "%s(%d) : %s\n", W2T(m_pszFileName), lLine, W2T(pszDescription));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fprintf(stderr, "%s(1) : %s\n", W2T(m_pszFileName), W2T(pszDescription));
|
||
|
}
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT ParseCommandLine(
|
||
|
int argc,
|
||
|
char * argv[],
|
||
|
WCHAR ** pszInFileName,
|
||
|
WCHAR ** pszOutFileName,
|
||
|
WCHAR ** pszHeaderFileName)
|
||
|
{
|
||
|
SPDBG_FUNC("ParseCommandLine");
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
// Our job is to come up with the three filenames from the command
|
||
|
// line arguments. We'll store them locally in cotask strings,
|
||
|
// and return them at the end
|
||
|
CSpDynamicString dstrInFileName;
|
||
|
CSpDynamicString dstrOutFileName;
|
||
|
CSpDynamicString dstrHeaderFileName;
|
||
|
|
||
|
for (int i = 1; SUCCEEDED(hr) && i < argc; i++)
|
||
|
{
|
||
|
// If this param looks like it's an option
|
||
|
if ((argv[i][0] == L'-') || (argv[i][0] == L'/'))
|
||
|
{
|
||
|
if (stricmp(&argv[i][1], "?") == 0)
|
||
|
{
|
||
|
// The invoker is asking for help, give it to them as if they specified an
|
||
|
// invalid argument
|
||
|
hr = E_INVALIDARG;
|
||
|
}
|
||
|
else if (i + 1 >= argc)
|
||
|
{
|
||
|
// The following arguments require an additional argument themsevles
|
||
|
// so if we don't have one, we're done
|
||
|
hr = E_INVALIDARG;
|
||
|
}
|
||
|
else if (stricmp(&argv[i][1], "o") == 0)
|
||
|
{
|
||
|
// Set the output filename if it hasn't already been set
|
||
|
if (dstrOutFileName.Length() != 0)
|
||
|
{
|
||
|
hr = E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
dstrOutFileName = argv[++i];
|
||
|
}
|
||
|
else if (stricmp(&argv[i][1], "h") == 0)
|
||
|
{
|
||
|
// Set the header filename if it hasn't already been set
|
||
|
if (dstrHeaderFileName.Length() != 0)
|
||
|
{
|
||
|
hr = E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
dstrHeaderFileName = argv[++i];
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Unknown option, we'll need to display usage
|
||
|
hr = E_INVALIDARG;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Set the filename if it hasn't already been set
|
||
|
if (dstrInFileName.Length() != 0)
|
||
|
{
|
||
|
hr = E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
dstrInFileName = argv[i];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// If we don't have an input file name, that's an error at this point
|
||
|
if (SUCCEEDED(hr) && dstrInFileName.Length() == 0)
|
||
|
{
|
||
|
hr = E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
// If we don't already have an output file name, make one up
|
||
|
// based on the input file name (replacing the .cfg if it's there)
|
||
|
if (SUCCEEDED(hr) && dstrOutFileName.Length() == 0)
|
||
|
{
|
||
|
dstrOutFileName = dstrInFileName;
|
||
|
|
||
|
if (dstrOutFileName.Length() >= 4 &&
|
||
|
wcsicmp(((const WCHAR *)dstrOutFileName) + dstrOutFileName.Length() - 4, L".xml") == 0)
|
||
|
{
|
||
|
wcscpy(((WCHAR *)dstrOutFileName) + dstrOutFileName.Length() - 4, L".cfg");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dstrOutFileName.Append(L".cfg");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// If we failed above, we need to display usage
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
fprintf(stderr, "%s [/o cfg_filename] [/h header_filename] input_filename\n", argv[0]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Pass back our filenames based on what we saw on the command line
|
||
|
*pszInFileName = dstrInFileName.Detach();
|
||
|
*pszOutFileName = dstrOutFileName.Detach();
|
||
|
*pszHeaderFileName = dstrHeaderFileName.Detach();
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT OpenFile(
|
||
|
const WCHAR * pszFileName,
|
||
|
DWORD dwDesiredAccess,
|
||
|
DWORD dwCreationDisposition,
|
||
|
const WCHAR * pszNewExtension,
|
||
|
CSpFileStream ** ppFileStream)
|
||
|
{
|
||
|
SPDBG_FUNC("OpenFile");
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
// Try to open the file
|
||
|
HANDLE hFile = g_Unicode.CreateFile(pszFileName, dwDesiredAccess, 0, NULL, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL);
|
||
|
if (hFile == INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
// If that failed, try again appending the extension first
|
||
|
if (pszNewExtension != NULL)
|
||
|
{
|
||
|
CSpDynamicString dstrFileNameWithExt;
|
||
|
dstrFileNameWithExt.Append2(pszFileName, pszNewExtension);
|
||
|
|
||
|
hFile = g_Unicode.CreateFile(dstrFileNameWithExt, dwDesiredAccess, 0, NULL, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// If we couldn't open the file, record the error
|
||
|
if (hFile == INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
hr = SpHrFromLastWin32Error();
|
||
|
}
|
||
|
|
||
|
// Create a new filestream object for that file
|
||
|
CSpFileStream * pFileStream;
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
*ppFileStream = new CSpFileStream(hFile);
|
||
|
if (*ppFileStream == NULL)
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// If we failed
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
// First we should let the invoker know that it failed
|
||
|
USES_CONVERSION;
|
||
|
fprintf(stderr, "Error: Error opening %s\n", W2T(pszFileName));
|
||
|
|
||
|
if (hFile != INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
CloseHandle(hFile);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT Compile(const WCHAR * pszInFileName, const WCHAR * pszOutFileName, const WCHAR * pszHeaderFileName)
|
||
|
{
|
||
|
SPDBG_FUNC("Compile");
|
||
|
HRESULT hr;
|
||
|
|
||
|
CComPtr<ISpGrammarCompiler> cpCompiler;
|
||
|
hr = cpCompiler.CoCreateInstance(CLSID_SpGrammarCompiler);
|
||
|
|
||
|
CComPtr<CSpFileStream> cpInStream;
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = OpenFile(pszInFileName, GENERIC_READ, OPEN_EXISTING, L".xml", &cpInStream);
|
||
|
}
|
||
|
|
||
|
CComPtr<CSpFileStream> cpOutStream;
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = OpenFile(pszOutFileName, GENERIC_WRITE, CREATE_ALWAYS, NULL, &cpOutStream);
|
||
|
}
|
||
|
|
||
|
CComPtr<CSpFileStream> cpHeaderStream;
|
||
|
if (SUCCEEDED(hr) && pszHeaderFileName != NULL)
|
||
|
{
|
||
|
hr = OpenFile(pszHeaderFileName, GENERIC_WRITE, CREATE_ALWAYS, NULL, &cpHeaderStream);
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
CError errorlog(pszInFileName);
|
||
|
hr = cpCompiler->CompileStream(cpInStream, cpOutStream, cpHeaderStream, NULL, &errorlog, 0);
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT Execute(int argc, char * argv[])
|
||
|
{
|
||
|
SPDBG_FUNC("Execute");
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
CSpDynamicString dstrInFileName, dstrOutFileName, dstrHeaderFileName;
|
||
|
hr = ParseCommandLine(argc, argv, &dstrInFileName, &dstrOutFileName, &dstrHeaderFileName);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = Compile(dstrInFileName, dstrOutFileName, dstrHeaderFileName);
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
fprintf(stderr, "Compilation successful!\n");
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
int main(int argc, char* argv[])
|
||
|
{
|
||
|
SPDBG_FUNC("main");
|
||
|
HRESULT hr;
|
||
|
hr = CoInitialize(NULL);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = Execute(argc, argv);
|
||
|
CoUninitialize();
|
||
|
}
|
||
|
|
||
|
return FAILED(hr) ? -1 : 0;
|
||
|
}
|