// 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 cpCompiler; hr = cpCompiler.CoCreateInstance(CLSID_SpGrammarCompiler); CComPtr cpInStream; if (SUCCEEDED(hr)) { hr = OpenFile(pszInFileName, GENERIC_READ, OPEN_EXISTING, L".xml", &cpInStream); } CComPtr cpOutStream; if (SUCCEEDED(hr)) { hr = OpenFile(pszOutFileName, GENERIC_WRITE, CREATE_ALWAYS, NULL, &cpOutStream); } CComPtr 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; }