// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.IO; using System.Text; namespace UnrealBuildTool { /// /// Parses include directives from cpp source files, to make dedicated PCHs /// static class CppIncludeParser { /// /// Copies include directives from one file to another, until an unsafe directive (or non-#include line) is found. /// /// Stream to read from /// Stream to write directives to public static void CopyIncludeDirectives(StreamReader Reader, StringBuilder Writer) { StringBuilder Token = new StringBuilder(); while (TryReadToken(Reader, Token)) { if (Token.Length > 1 || Token[0] != '\n') { if (Token.Length != 1 || Token[0] != '#') { break; } if (!TryReadToken(Reader, Token)) { break; } string Directive = Token.ToString(); if (Directive == "pragma") { if (!TryReadToken(Reader, Token) || Token.ToString() != "once") { break; } if (!TryReadToken(Reader, Token) || Token.ToString() != "\n") { break; } } else if (Directive == "include") { if (!TryReadToken(Reader, Token) || Token[0] != '\"') { break; } string IncludeFile = Token.ToString(); if (!IncludeFile.EndsWith(".h\"") && !IncludeFile.EndsWith(".h>")) { break; } if (IncludeFile.Equals("\"RequiredProgramMainCPPInclude.h\"", StringComparison.OrdinalIgnoreCase)) { break; } if (!TryReadToken(Reader, Token) || Token.ToString() != "\n") { break; } Writer.Append("#include ").AppendLine(IncludeFile); } else { break; } } } } /// /// Reads an individual token from the input stream /// /// Stream to read from /// Buffer to store token read from the stream /// True if a token was read, false otherwise static bool TryReadToken(StreamReader Reader, StringBuilder Token) { Token.Clear(); int NextChar; for (; ; ) { NextChar = Reader.Read(); if (NextChar == -1) { return false; } if (NextChar != ' ' && NextChar != '\t' && NextChar != '\r') { if (NextChar != '/') { break; } else if (Reader.Peek() == '/') { Reader.Read(); for (; ; ) { NextChar = Reader.Read(); if (NextChar == -1) { return false; } if (NextChar == '\n') { break; } } } else if (Reader.Peek() == '*') { Reader.Read(); for (; ; ) { NextChar = Reader.Read(); if (NextChar == -1) { return false; } if (NextChar == '*' && Reader.Peek() == '/') { break; } } Reader.Read(); } else { break; } } } Token.Append((char)NextChar); if (Char.IsLetterOrDigit((char)NextChar)) { for (; ; ) { NextChar = Reader.Read(); if (NextChar == -1 || !Char.IsLetterOrDigit((char)NextChar)) { break; } Token.Append((char)NextChar); } } else if (NextChar == '\"' || NextChar == '<') { for (; ; ) { NextChar = Reader.Read(); if (NextChar == -1) { break; } Token.Append((char)NextChar); if (NextChar == '\"' || NextChar == '>') { break; } } } return true; } } }