| Index: tools/supalink/supalink.cpp
|
| diff --git a/tools/supalink/supalink.cpp b/tools/supalink/supalink.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..0c6bd878ddcf8d4282e5397ba913095360495976
|
| --- /dev/null
|
| +++ b/tools/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)
|
| +{
|
| + fprintf(stdout, "supalink fatal error: %s\n", msg);
|
| + exit(1);
|
| +}
|
| +
|
| +static string ErrorMessageToString(DWORD err)
|
| +{
|
| + LPTSTR msgBuf = NULL;
|
| + 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);
|
| + 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();
|
| +}
|
|
|