168 lines
5.5 KiB
C++
168 lines
5.5 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "UbaProcessStartInfoHolder.h"
|
|
#include "UbaConfig.h"
|
|
|
|
namespace uba
|
|
{
|
|
bool ProcessStartInfoHolder::Expand()
|
|
{
|
|
#if PLATFORM_WINDOWS
|
|
// Special handling to avoid calling cmd.exe if not needed
|
|
if (!Contains(application, TC("cmd.exe")))
|
|
return false;
|
|
|
|
const tchar* argsBegin = argumentsStr.c_str();
|
|
|
|
// Check if application is repeated as first argument, in that case consume it
|
|
const tchar* firstArgBegin = argsBegin;
|
|
const tchar* firstArgEnd = nullptr;
|
|
if (*firstArgBegin == '\"')
|
|
{
|
|
++firstArgBegin;
|
|
firstArgEnd = TStrchr(firstArgBegin, '\"');
|
|
}
|
|
else
|
|
firstArgEnd = TStrchr(firstArgBegin, ' ');
|
|
if (!firstArgEnd)
|
|
return false;
|
|
return InternalExpand(firstArgBegin, firstArgEnd);
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
UBA_NOINLINE bool ProcessStartInfoHolder::InternalExpand(const tchar* firstArgBegin, const tchar* firstArgEnd)
|
|
{
|
|
// Separate function to hide away large stack object
|
|
#if PLATFORM_WINDOWS
|
|
const tchar* argsBegin = argumentsStr.c_str();
|
|
const tchar* argsEnd = argsBegin + argumentsStr.size();
|
|
|
|
StringBuffer<32*1024> commands;
|
|
commands.Append(firstArgBegin, firstArgEnd - firstArgBegin);
|
|
if (commands.Contains(application))
|
|
argsBegin = firstArgEnd;
|
|
while (argsBegin && *argsBegin == ' ')
|
|
++argsBegin;
|
|
commands.Clear();
|
|
|
|
|
|
// Parse switches... only supported is /C right now
|
|
if (!StartsWith(argsBegin, TC("/C ")))
|
|
return false;
|
|
argsBegin += 3;
|
|
while (argsBegin && *argsBegin == ' ')
|
|
++argsBegin;
|
|
|
|
if (argsBegin && *argsBegin == '/') // Unknown switch, don't try to expand cmd
|
|
return false;
|
|
|
|
if (argsBegin && *argsBegin == '\"')
|
|
{
|
|
++argsBegin;
|
|
--argsEnd;
|
|
}
|
|
while (argsBegin && *argsBegin == ' ')
|
|
++argsBegin;
|
|
|
|
commands.Append(argsBegin, argsEnd - argsBegin);
|
|
|
|
// It could be that there is just a chain of commands to set working dir, in that case we strip out cmd.exe
|
|
const tchar* andPos = nullptr;
|
|
if (commands.Contains(TC(" && "), true, &andPos))
|
|
{
|
|
if (Contains(andPos + 4, TC(" && "))) // If more than one && we don't try to expand cmd.exe
|
|
return false;
|
|
if (!commands.StartsWith(TC("cd /D"))) // First command is not cd, don't try to expand cmd.exe
|
|
return false;
|
|
const tchar* workDirStart = commands.data + 6;
|
|
workingDirStr.assign(workDirStart, andPos - workDirStart);
|
|
|
|
StringBuffer<> fixed;
|
|
FixPath(workingDirStr.data(), nullptr, 0, fixed);
|
|
workingDirStr = fixed.data;
|
|
workingDir = workingDirStr.c_str();
|
|
|
|
const tchar* commandLine = andPos + 4;
|
|
while (*commandLine && *commandLine == ' ')
|
|
++commandLine;
|
|
const tchar* applicationBegin = commandLine;
|
|
const tchar* applicationEnd = nullptr;
|
|
if (*applicationBegin == '\"')
|
|
{
|
|
++applicationBegin;
|
|
applicationEnd = TStrchr(applicationBegin, '\"');
|
|
}
|
|
else
|
|
applicationEnd = TStrchr(applicationBegin, ' ');
|
|
if (!applicationEnd)
|
|
applicationEnd = applicationBegin + TStrlen(applicationBegin);
|
|
applicationStr.assign(applicationBegin, applicationEnd - applicationBegin);
|
|
FixPath(applicationStr.data(), nullptr, 0, fixed.Clear());
|
|
applicationStr = fixed.data;
|
|
application = applicationStr.c_str();
|
|
argsBegin = *applicationEnd == '\"' ? applicationEnd + 1 : applicationEnd;
|
|
while (*argsBegin && *argsBegin == ' ')
|
|
++argsBegin;
|
|
argumentsStr = argsBegin;
|
|
arguments = argumentsStr.c_str();
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
// TODO: This is super hacky... but we don't want to spawn the cmd.exe just to copy a file since the overhead can be half a second
|
|
// "C:\WINDOWS\system32\cmd.exe" /C "copy /Y "E:\dev\fn\Engine\Source\Runtime\RenderCore\RenderCore.natvis" "E:\dev\fn\Engine\Intermediate\Build\Win64\x64\UnrealPak\Development\RenderCore\RenderCore.natvis" 1>nul"
|
|
if (!commands.StartsWith(TC("copy /Y \"")))
|
|
return false;
|
|
|
|
const tchar* fromFileBegin = commands.data + 9;
|
|
const tchar* fromFileEnd = TStrchr(fromFileBegin, '\"');
|
|
if (!fromFileEnd)
|
|
return false;
|
|
const tchar* toFileBegin = TStrchr(fromFileEnd + 1, '\"');
|
|
if (!toFileBegin)
|
|
return false;
|
|
++toFileBegin;
|
|
const tchar* toFileEnd = TStrchr(toFileBegin, '\"');
|
|
if (!toFileEnd)
|
|
return false;
|
|
|
|
applicationStr = TC("ubacopy");
|
|
application = applicationStr.c_str();
|
|
argumentsStr = fromFileBegin;
|
|
arguments = argumentsStr.c_str();
|
|
return true;
|
|
}
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
void ProcessStartInfoHolder::Apply(const Config& config, const uba::tchar* configTable)
|
|
{
|
|
const ConfigTable* tablePtr = config.GetTable(configTable);
|
|
if (!tablePtr)
|
|
return;
|
|
const ConfigTable& table = *tablePtr;
|
|
if (table.GetValueAsString(applicationStr, TC("Application")))
|
|
application = applicationStr.c_str();
|
|
if (table.GetValueAsString(argumentsStr, TC("Arguments")))
|
|
arguments = argumentsStr.c_str();
|
|
if (table.GetValueAsString(workingDirStr, TC("WorkingDir")))
|
|
workingDir = workingDirStr.c_str();
|
|
if (table.GetValueAsString(descriptionStr, TC("Description")))
|
|
description = descriptionStr.c_str();
|
|
if (table.GetValueAsString(logFileStr, TC("LogFile")))
|
|
logFile = logFileStr.c_str();
|
|
if (table.GetValueAsString(breadcrumbsStr, TC("Breadcrumbs")))
|
|
breadcrumbs = breadcrumbsStr.c_str();
|
|
|
|
table.GetValueAsU32(priorityClass, TC("PriorityClass"));
|
|
table.GetValueAsBool(trackInputs, TC("TrackInputs"));
|
|
table.GetValueAsBool(useCustomAllocator, TC("UseCustomAllocator"));
|
|
table.GetValueAsBool(writeOutputFilesOnFail, TC("WriteOutputFilesOnFail"));
|
|
table.GetValueAsBool(startSuspended, TC("StartSuspended"));
|
|
table.GetValueAsU64(rootsHandle, TC("RootsHandle"));
|
|
}
|
|
}
|