Index: tools/win/supalink/supalink.cpp |
diff --git a/tools/win/supalink/supalink.cpp b/tools/win/supalink/supalink.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..0c6bd878ddcf8d4282e5397ba913095360495976 |
--- /dev/null |
+++ b/tools/win/supalink/supalink.cpp |
@@ -0,0 +1,211 @@ |
+// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include <windows.h> |
+#include <stdio.h> |
+#include <stdlib.h> |
+#include <string> |
+ |
+using namespace std; |
+ |
+// Don't use stderr for errors because VS has large buffers on them, leading |
+// to confusing error output. |
+static void Fatal(const char* msg) |
+{ |
jam
2011/09/27 22:10:34
nit: brace bracket after function, see style guide
|
+ fprintf(stdout, "supalink fatal error: %s\n", msg); |
+ exit(1); |
+} |
+ |
+static string ErrorMessageToString(DWORD err) |
+{ |
+ LPTSTR msgBuf = NULL; |
jam
2011/09/27 22:10:34
msg_buf (see style guide)
|
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, |
+ NULL, |
+ err, |
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), |
+ (LPTSTR)&msgBuf, |
+ 0, |
+ NULL); |
+ string ret(msgBuf); |
+ LocalFree(msgBuf); |
+ return ret; |
+} |
+ |
+ |
+static void Fallback(const char* msg = 0) |
+{ |
+ if (msg) |
+ { |
+ fprintf(stdout, |
+ "supalink failed (%s), trying to fallback to standard link.\n", |
+ msg); |
+ fprintf(stdout, "Original command line: %s\n", GetCommandLine()); |
+ fflush(stdout); |
+ } |
+ |
+ STARTUPINFO startupInfo = { sizeof(STARTUPINFO) }; |
+ PROCESS_INFORMATION processInfo; |
+ DWORD exitCode; |
+ |
+ string origCmd(GetCommandLine()); |
+ |
+ const char* searchFor[] = { |
+ "link.exe\" ", |
+ "LINK.EXE\" ", |
+ "link.EXE\" ", |
+ "link\" ", |
+ "LINK\" ", |
+ "link.exe ", |
+ "LINK.EXE ", |
+ "link.EXE ", |
+ "link ", |
+ "LINK ", |
+ }; |
+ string cmd; |
+ string replaceWith = "link.exe.supalink_orig.exe"; |
+ for (size_t i = 0; i < sizeof(searchFor) / sizeof(searchFor[0]); ++i) |
+ { |
+ string linkexe = searchFor[i]; |
+ string::size_type at = origCmd.find(linkexe, 0); |
+ if (at == string::npos) |
+ continue; |
+ if (linkexe[linkexe.size() - 2] == '"') |
+ replaceWith += "\" "; |
+ else |
+ replaceWith += " "; |
+ cmd = origCmd.replace(at, linkexe.size(), replaceWith); |
+ break; |
+ } |
+ if (cmd == "") |
+ { |
+ fprintf(stdout, "Original run '%s'\n", origCmd.c_str()); |
+ Fatal("Couldn't find link.exe (or similar) in command line"); |
+ } |
+ |
+ if (getenv("SUPALINK_DEBUG")) |
+ { |
+ fprintf(stdout, " running '%s'\n", cmd.c_str()); |
+ fflush(stdout); |
+ } |
+ if (!CreateProcess(NULL, |
+ (LPSTR)cmd.c_str(), |
+ NULL, |
+ NULL, |
+ TRUE, |
+ 0, |
+ NULL, |
+ NULL, |
+ &startupInfo, &processInfo)) |
+ { |
+ string error = ErrorMessageToString(GetLastError()); |
+ Fatal(error.c_str()); |
+ } |
+ WaitForSingleObject(processInfo.hProcess, INFINITE); |
+ GetExitCodeProcess(processInfo.hProcess, &exitCode); |
+ CloseHandle(processInfo.hProcess); |
+ CloseHandle(processInfo.hThread); |
+ exit(exitCode); |
+} |
+ |
+wstring SlurpFile(const char* path) |
+{ |
+ FILE* f = fopen(path, "rb, ccs=UNICODE"); |
+ if (!f) Fallback("couldn't read file"); |
+ fseek(f, 0, SEEK_END); |
+ long len = ftell(f); |
+ rewind(f); |
+ wchar_t* data = (wchar_t*)malloc(len); |
jam
2011/09/27 22:10:34
use reinterpret_cast (see style guide)
|
+ fread(data, 1, len, f); |
+ fclose(f); |
+ wstring ret(data, len/sizeof(wchar_t)); |
+ free(data); |
+ return ret; |
+} |
+ |
+void DumpFile(const char* path, wstring& contents) |
+{ |
+ FILE* f = fopen(path, "wb, ccs=UTF-16LE"); |
+ if (!f) Fallback("couldn't write file"); |
+ |
+ fwrite(contents.c_str(), sizeof(wchar_t), contents.size(), f); |
+ if (ferror(f)) Fatal("failed during response rewrite"); |
+ fclose(f); |
+} |
+ |
+// Input command line is assumed to be of the form: |
+// |
+// link.exe @C:\src\...\RSP00003045884740.rsp /NOLOGO /ERRORREPORT:PROMPT |
+// |
+// Specifically, we parse & hack the contents of argv[1] and pass the rest |
+// onwards. |
+// |
+// %REALLINK%.supalink_orig.exe |
+int main(int argc, char** argv) |
+{ |
+ ULONGLONG startTime = 0, endTime; |
+ //fprintf(stderr, "GetCommandLine(): '%s'\n", GetCommandLine()); |
+ //fflush(stderr); |
+ |
+ int rspFileIndex = -1; |
+ |
+ if (argc < 2) |
+ Fallback("too few commmand line args"); |
+ |
+ for (int i = 1; i < argc; ++i) |
+ { |
+ if (argv[i][0] == '@') |
+ { |
+ rspFileIndex = i; |
+ break; |
+ } |
+ } |
+ |
+ if (rspFileIndex == -1) |
+ Fallback("couldn't find a response file in argv"); |
+ |
+ if (getenv("SUPALINK_DEBUG")) |
+ startTime = GetTickCount64(); |
+ |
+ wstring rsp = SlurpFile(&argv[rspFileIndex][1]); |
+ |
+ // The first line of this file is all we try to fix. It's a bunch of |
+ // quoted space separated items. Simplest thing seems to be replacing " " |
+ // with "\n". So, just slurp the file, replace, spit it out to the same |
+ // file and continue on our way. |
+ |
+ // Took about .5s when using the naive .replace loop to replace " " with |
+ // "\r\n" so write the silly loop instead. |
+ wstring fixed; |
+ fixed.reserve(rsp.size() * 2); |
+ |
+ for (const wchar_t* s = rsp.c_str(); *s;) |
+ { |
+ if (*s == '"' && *(s + 1) == ' ' && *(s + 2) == '"') |
+ { |
+ fixed += L"\"\r\n\""; |
+ s += 3; |
+ } |
+ else |
+ { |
+ fixed += *s++; |
+ } |
+ } |
+ |
+ DumpFile(&argv[rspFileIndex][1], fixed); |
+ |
+ if (getenv("SUPALINK_DEBUG")) |
+ { |
+ string backupCopy(&argv[rspFileIndex][1]); |
+ backupCopy += ".copy"; |
+ DumpFile(backupCopy.c_str(), fixed); |
+ |
+ endTime = GetTickCount64(); |
+ |
+ fprintf(stdout, |
+ " took %.2fs to modify @rsp file\n", |
+ (endTime - startTime) / 1000.0); |
+ } |
+ |
+ Fallback(); |
+} |