Files
GacUI/Tools/Executables/CodePack/Codepack_Combine.cpp
2023-04-09 03:49:54 -07:00

212 lines
6.3 KiB
C++

#include "Codepack.h"
FilePath GetCommonFolder(
const List<FilePath>& paths
)
{
auto folder = paths[0].GetFolder();
while (true)
{
if (From(paths).All([&](const FilePath& path)
{
return INVLOC.StartsWith(path.GetFullPath(), folder.GetFullPath() + WString::FromChar(folder.Delimiter), Locale::IgnoreCase);
}))
{
return folder;
}
folder = folder.GetFolder();
}
CHECK_FAIL(L"Cannot process files across multiple drives.");
}
void CollectConditions(
Group<WString, WString>& categorizedConditions,
Group<FilePath, Tuple<WString, FilePath>>& conditions,
const FilePath& file,
const Dictionary<FilePath, WString>& inputFileToOutputFiles
)
{
vint index = conditions.Keys().IndexOf(file);
if (index != -1)
{
for (auto [condition, path] : conditions.GetByIndex(index))
{
auto includeFile = inputFileToOutputFiles[path];
if (!categorizedConditions.Contains(condition, includeFile))
{
categorizedConditions.Add(condition, includeFile);
}
}
}
}
void CombineWriteHeader(
List<WString>& lines,
const Dictionary<FilePath, WString>& inputFileToOutputFiles,
Group<FilePath, Tuple<WString, FilePath>>& conditionOns,
Group<FilePath, Tuple<WString, FilePath>>& conditionOffs,
const List<FilePath>& files,
LazyList<WString> externalIncludes
)
{
lines.Add(L"/***********************************************************************");
lines.Add(L"THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY");
lines.Add(L"DEVELOPER: Zihan Chen(vczh)");
lines.Add(L"***********************************************************************/");
for (auto path : externalIncludes)
{
lines.Add(L"#include \"" + path + L"\"");
}
{
Group<WString, WString> categorizedConditionOns, categorizedConditionOffs;
for (auto file : files)
{
CollectConditions(categorizedConditionOns, conditionOns, file, inputFileToOutputFiles);
CollectConditions(categorizedConditionOffs, conditionOffs, file, inputFileToOutputFiles);
}
for (vint i = 0; i < categorizedConditionOns.Count(); i++)
{
lines.Add(L"#ifdef " + categorizedConditionOns.Keys()[i]);
const auto& onFiles = categorizedConditionOns.GetByIndex(i);
for (auto onFile : onFiles)
{
lines.Add(L"#include \"" + inputFileToOutputFiles[onFile] + L"\"");
}
lines.Add(L"#endif");
}
for (vint i = 0; i < categorizedConditionOffs.Count(); i++)
{
lines.Add(L"#ifndef " + categorizedConditionOffs.Keys()[i]);
const auto& offFiles = categorizedConditionOffs.GetByIndex(i);
for (auto offFile : offFiles)
{
lines.Add(L"#include \"" + offFile + L".h\"");
}
lines.Add(L"#endif");
}
}
}
void Combine(
const Dictionary<FilePath, WString>& inputFileToOutputFiles, // (in)
const Dictionary<WString, FilePath>& skippedImportFiles, // (in)
Dictionary<FilePath, LazyList<FilePath>>& cachedFileToIncludes, // (cache)
Group<FilePath, Tuple<WString, FilePath>>& conditionOns, // (out)
Group<FilePath, Tuple<WString, FilePath>>& conditionOffs, // (out)
const List<FilePath>& files, // (in)
FilePath outputFilePath, //
FilePath outputIncludeFilePath, //
SortedList<WString>& systemIncludes, //
LazyList<WString> externalIncludes //
)
{
auto workingDir = outputFilePath.GetFolder();
List<FilePath> sortedFiles;
{
PartialOrderingProcessor popFiles;
Group<FilePath, FilePath> depGroup;
for (auto file : files)
{
for (auto dep : GetIncludedFiles(file, skippedImportFiles, cachedFileToIncludes, conditionOns, conditionOffs))
{
if (files.Contains(dep))
{
depGroup.Add(file, dep);
}
}
}
popFiles.InitWithGroup(files, depGroup);
popFiles.Sort();
bool needExit = false;
for (vint i = 0; i < popFiles.components.Count(); i++)
{
auto& component = popFiles.components[i];
sortedFiles.Add(files[component.firstNode[0]]);
if (component.nodeCount > 1)
{
Console::SetColor(true, false, false, true);
Console::WriteLine(
L"Error: Cycle dependency found in categories: "
+ From(component.firstNode, component.firstNode + component.nodeCount)
.Select([&](vint nodeIndex) { return L"\r\n" + files[nodeIndex].GetFullPath(); })
.Aggregate([](const WString& a, const WString& b) {return a + b; })
+ L"\r\n.");
Console::SetColor(true, true, true, false);
needExit = true;
}
}
CHECK_ERROR(!needExit, L"Cycle dependency is not allowed");
}
{
List<WString> lines;
CombineWriteHeader(lines, inputFileToOutputFiles, conditionOns, conditionOffs, files, externalIncludes);
{
auto prefix = GetCommonFolder(files);
for (auto file : From(sortedFiles).Intersect(files))
{
lines.Add(L"");
lines.Add(L"/***********************************************************************");
lines.Add(wupper(prefix.GetRelativePathFor(file)));
lines.Add(L"***********************************************************************/");
StringReader reader(ReadFile(file));
bool skip = false;
while (!reader.IsEnd())
{
auto line = reader.ReadLine();
Ptr<RegexMatch> match;
if ((match = regexInstruction.MatchHead(line)))
{
auto name = match->Groups()[instruction_name][0].Value();
if (name == L"BeginIgnore")
{
skip = true;
}
else if (name == L"EndIgnore")
{
skip = false;
}
}
else if (!skip)
{
if ((match = regexSystemInclude.MatchHead(line)))
{
auto systemFile = match->Groups()[systemInclude_path][0].Value();
if (skippedImportFiles.Keys().Contains(systemFile)) continue;
if (systemIncludes.Contains(systemFile)) continue;
systemIncludes.Add(systemFile);
lines.Add(line);
}
else if (!regexInclude.MatchHead(line))
{
lines.Add(line);
}
}
}
}
}
File(outputFilePath).WriteAllLines(lines, true, BomEncoder::Utf8);
}
{
List<WString> lines;
CombineWriteHeader(lines, inputFileToOutputFiles, conditionOns, conditionOffs, files, externalIncludes);
lines.Add(L"");
{
auto prefix = outputIncludeFilePath.GetFolder();
for (auto file : From(sortedFiles).Intersect(files))
{
lines.Add(L"#include \"" + prefix.GetRelativePathFor(file) + L"\"");
}
}
File(outputIncludeFilePath).WriteAllLines(lines, true, BomEncoder::Utf8);
}
Console::SetColor(false, true, false, true);
Console::WriteLine(L"Succeeded to write: " + outputFilePath.GetFullPath());
Console::SetColor(true, true, true, false);
}