// add this to the bottom of convert.c #define WIN32_LEAN_AND_MEAN #include // Exported functions // InvokeCompilerPassW - From VS2008 and up, returns BOOL on whether to stop the compiling process // (non-zero stops it) // InvokeCompilerPass - All the way back to VC6 (and probably before) // these must be exported with normal stdcall decoration (eg underscore prepended, @ appended) // AbortCompilerPass - all versions, called when build cancelled from the IDE or Ctrl-C in command window #define FIND_FILE_FLAG(argc, argv, fileArg, flag, keepFlag, keepFlagSeen, compFn) \ { \ for(int i = 0; (i < argc) && !(fileArg && keepFlagSeen); ++i) \ { \ if(compFn(ppArgv[i], flag) == 0) \ { \ if((argc + 1) == argc) \ { \ return 1; \ } \ else \ { \ fileArg = i + 1; \ } \ } \ else if(compFn(ppArgv[i], keepFlag) == 0) \ { \ keepFlagSeen = 1; \ } \ } \ } typedef int (__stdcall*pfnInvokeCompilerPassW)(int argc, wchar_t** ppArgv, int flag, void** pphCLUIInstance); typedef int (__stdcall*pfnInvokeCompilerPass)(int argc, char** ppArgv, int flag); typedef void (__stdcall*pfnAbortCompilerPass)(int val); pfnInvokeCompilerPassW g_c1InvokeW = NULL; pfnInvokeCompilerPass g_c1Invoke = NULL; pfnAbortCompilerPass g_c1Abort = NULL; int load_c1_exports() { wchar_t dllName[MAX_PATH]; wchar_t* pFileNamePortion = NULL; DWORD nameChars = 0; if((nameChars = GetModuleFileNameW(GetModuleHandle(NULL), dllName, ARRAYSIZE(dllName)) != 0) && (pFileNamePortion = wcsrchr(dllName, L'\\')) && ((nameChars - (pFileNamePortion - dllName)) >= 6) ) { HMODULE hC1 = NULL; wcsncpy(pFileNamePortion, L"c1.dll", 6); hC1 = LoadLibraryExW(dllName, NULL, 0); if(hC1) { g_c1InvokeW = (pfnInvokeCompilerPassW)GetProcAddress(hC1, "_InvokeCompilerPassW@16"); g_c1Invoke = (pfnInvokeCompilerPass)GetProcAddress(hC1, "_InvokeCompilerPass@12"); g_c1Abort = (pfnAbortCompilerPass)GetProcAddress(hC1, "_AbortCompilerPass@4"); return (g_c1InvokeW || g_c1Invoke) && g_c1Abort; } } return 0; } #define pass_on_args(argc, argv, flag, pphClui) \ pphClui ? g_c1InvokeW(argc, argv, flag, pphClui) : g_c1Invoke(argc, argv, flag) int get_out_file_name(char* pBuffer, size_t arrSize, int origDir, const char* pInFile) { char* pNewFile = NULL; if(origDir) { return snprintf(pBuffer, arrSize, "%s.c99.txt", pInFile); } if((pNewFile = tmpnam(NULL))) { strncpy(pBuffer, pNewFile, arrSize); return 1; } else return -1; } int do_translation(const char* pInFile, char** ppOutFile, int keepFile) { char outFile[MAX_PATH] = {0}; if(get_out_file_name(outFile, ARRAYSIZE(outFile), keepFile, pInFile) == -1) { return -1; } return convert(pInFile, outFile); } char* convert_to_narrow(const wchar_t* pStr) { char* pRet = NULL; size_t reqd = wcstombs(NULL, pStr, 0); if((reqd == (size_t)-1) || ((pRet = malloc(reqd)) == NULL) || (wcstombs(pRet, pStr, reqd) == (size_t)-1) ) { free(pRet); return NULL; } return pRet; } wchar_t* convert_to_wide(const char* pStr) { wchar_t* pRet = NULL; size_t reqd = mbstowcs(NULL, pStr, 0); if((reqd == (size_t)-1) || ((pRet = malloc(reqd)) == NULL) || (mbstowcs(pRet, pStr, reqd) == (size_t)-1) ) { free(pRet); return NULL; } return pRet; } __declspec(dllexport) int __stdcall InvokeCompilerPassW(int argc, wchar_t** ppArgv, int flag, void** pphCLUIInstance) { int c1Ret = 0; int fileArgument = 0; int keepFile = 0; char* pOutFile = NULL; char* pInFileMb = NULL; wchar_t* pInFileOrig = NULL; wchar_t* pOutFileWc = NULL; wchar_t** ppFileArgPtr = NULL; if(!load_c1_exports()) { printf("c99to89 - Couldn't find exports in c1.dll"); return -1; } // -f is the argument switch for input file FIND_FILE_FLAG(argc, argv, fileArgument, L"-f", L"-keep", keepFile, wcscmp); ppFileArgPtr = &ppArgv[fileArgument]; pInFileOrig = *ppFileArgPtr; if(_waccess(pInFileOrig, 04) == -1) { return -1; } if((pInFileMb = convert_to_narrow(pInFileOrig)) == NULL) { return -1; } // Don't need pInFileMb after this // so instead of putting it in both paths or putting the result in // a temporary (hah!) I do this. // The bitwise or is intentional, as is the flagrant abuse of // the comma operator. if((do_translation(pInFileMb, &pOutFile, keepFile) | (free(pInFileMb), 0)) || ((pOutFileWc = convert_to_wide(pOutFile)) == NULL) ) { if(pOutFile) { unlink(pOutFile); free(pOutFile); } return -1; } // update the file argument with our new file // and send to the compiler proper *ppFileArgPtr = pOutFileWc; c1Ret = pass_on_args(argc, ppArgv, flag, pphCLUIInstance); if(!keepFile) { unlink(pOutFile); } free(pOutFileWc); free(pOutFile); // restore the original name to the arguments // so the caller can do the approriate freeing // at this point, the proper front-end has written its bits to the // temporary file. Further passes shouldn't use the original file *ppFileArgPtr = pInFileOrig; return c1Ret; } __declspec(dllexport) int __stdcall InvokeCompilerPass(int argc, char** ppArgv, int flag) { int c1Ret = 0; int fileArgument = 0; int keepFile = 0; char* pOrigFileName = NULL; char* pOutFile = NULL; char** ppFileArgPtr = NULL; if(!load_c1_exports()) { printf("c99to89 - Couldn't find exports in c1.dll"); return -1; } // -f is the argument switch for input file FIND_FILE_FLAG(argc, ppArgv, fileArgument, "-f", "-keep", keepFile, strcmp); ppFileArgPtr = &ppArgv[fileArgument]; if(access(*ppFileArgPtr, 04) == -1) { return -1; } pOrigFileName = *ppFileArgPtr; if(do_translation(pOrigFileName, &pOutFile, keepFile) == -1) { if(pOutFile) { unlink(pOutFile); free(pOutFile); } return -1; } // update the file argument with our new file // and send to the compiler proper *ppFileArgPtr = pOutFile; c1Ret = pass_on_args(argc, ppArgv, flag, NULL); if(!keepFile) { unlink(pOutFile); } // restore the original name to the arguments // so the caller can do the approriate freeing // at this point, the proper front-end has written its bits to the // temporary file. Further passes shouldn't use the original file *ppFileArgPtr = pOrigFileName; return c1Ret; } __declspec(dllexport) void __stdcall AbortCompilerPass(int val) { // just forward it g_c1Abort(val); }