/// <summary> /// Parse the first include directive from a source file /// </summary> /// <param name="SourceFile">The source file to parse</param> /// <returns>The first include directive</returns> static string ParseFirstInclude(FileReference SourceFile) { bool bMatchImport = SourceFile.HasExtension(".m") || SourceFile.HasExtension(".mm"); using (StreamReader Reader = new StreamReader(SourceFile.FullName, true)) { for (;;) { string Line = Reader.ReadLine(); if (Line == null) { return(null); } Match IncludeMatch = IncludeRegex.Match(Line); if (IncludeMatch.Success) { return(IncludeMatch.Groups[1].Value); } if (bMatchImport) { Match ImportMatch = ImportRegex.Match(Line); if (ImportMatch.Success) { return(IncludeMatch.Groups[1].Value); } } } } }
/// <summary> /// Generates documentation files for the available settings, by merging the XML documentation from the compiler. /// </summary> /// <param name="OutputFile">The documentation file to write</param> public static void WriteDocumentation(FileReference OutputFile) { // Find all the configurable types List <Type> ConfigTypes = FindConfigurableTypes(); // Find all the configurable fields from the given types Dictionary <string, Dictionary <string, FieldInfo> > CategoryToFields = new Dictionary <string, Dictionary <string, FieldInfo> >(); FindConfigurableFields(ConfigTypes, CategoryToFields); CategoryToFields = CategoryToFields.Where(x => x.Value.Count > 0).ToDictionary(x => x.Key, x => x.Value); // Get the path to the XML documentation FileReference InputDocumentationFile = new FileReference(Assembly.GetExecutingAssembly().Location).ChangeExtension(".xml"); if (!FileReference.Exists(InputDocumentationFile)) { throw new BuildException("Generated assembly documentation not found at {0}.", InputDocumentationFile); } // Read the documentation XmlDocument InputDocumentation = new XmlDocument(); InputDocumentation.Load(InputDocumentationFile.FullName); // Make sure we can write to the output file if (FileReference.Exists(OutputFile)) { FileReference.MakeWriteable(OutputFile); } else { DirectoryReference.CreateDirectory(OutputFile.Directory); } // Generate the documentation file if (OutputFile.HasExtension(".udn")) { WriteDocumentationUDN(OutputFile, InputDocumentation, CategoryToFields); } else if (OutputFile.HasExtension(".html")) { WriteDocumentationHTML(OutputFile, InputDocumentation, CategoryToFields); } else { throw new BuildException("Unable to detect format from extension of output file ({0})", OutputFile); } // Success! Log.TraceInformation("Written documentation to {0}.", OutputFile); }
/// <summary> /// Collects all header files included in a source file /// </summary> /// <param name="ProjectFile"></param> /// <param name="SourceFile"></param> /// <param name="FileToRead"></param> /// <param name="FileContents"></param> /// <param name="InstalledFolder"></param> /// <param name="StartIndex"></param> /// <param name="EndIndex"></param> private static List <DependencyInclude> CollectHeaders(FileReference ProjectFile, FileReference SourceFile, string FileToRead, string FileContents, string InstalledFolder, int StartIndex, int EndIndex) { List <DependencyInclude> Result = new List <DependencyInclude>(); Match M = CPPHeaderRegex.Match(FileContents, StartIndex, EndIndex - StartIndex); CaptureCollection Captures = M.Groups["HeaderFile"].Captures; Result.Capacity = Result.Count; foreach (Capture C in Captures) { string HeaderValue = C.Value; if (HeaderValue.IndexOfAny(Path.GetInvalidPathChars()) != -1) { throw new BuildException("In {0}: An #include statement contains invalid characters. You might be missing a double-quote character. (\"{1}\")", FileToRead, C.Value); } //@TODO: The intermediate exclusion is to work around autogenerated absolute paths in Module.SomeGame.cpp style files bool bCheckForBackwardSlashes = FileToRead.StartsWith(InstalledFolder) || ((ProjectFile != null) && new FileReference(FileToRead).IsUnderDirectory(ProjectFile.Directory)); if (bCheckForBackwardSlashes && !FileToRead.Contains("Intermediate") && !FileToRead.Contains("ThirdParty") && HeaderValue.IndexOf('\\', 0) >= 0) { throw new BuildException("In {0}: #include \"{1}\" contains backslashes ('\\'), please use forward slashes ('/') instead.", FileToRead, C.Value); } HeaderValue = Utils.CleanDirectorySeparators(HeaderValue); Result.Add(new DependencyInclude(HeaderValue)); } // also look for #import in objective C files if (SourceFile.HasExtension(".MM") || SourceFile.HasExtension(".M")) { M = MMHeaderRegex.Match(FileContents, StartIndex, EndIndex - StartIndex); Captures = M.Groups["HeaderFile"].Captures; Result.Capacity += Captures.Count; foreach (Capture C in Captures) { Result.Add(new DependencyInclude(C.Value)); } } return(Result); }
/// <summary> /// Checks if the given file is part of the working set /// </summary> /// <param name="File">File to check</param> /// <returns>True if the file is part of the working set, false otherwise</returns> public bool Contains(FileReference File) { // Generated .cpp files should never be treated as part of the working set if (File.HasExtension(".gen.cpp")) { return(false); } // Check if the file is read-only try { return(!FileReference.GetAttributes(File).HasFlag(FileAttributes.ReadOnly)); } catch (FileNotFoundException) { return(false); } }
/// <summary> /// Reads dependencies from the given file. /// </summary> /// <param name="InputFile">The file to read from</param> /// <returns>List of included dependencies</returns> static List <FileItem> ReadDependenciesFile(FileReference InputFile) { if (InputFile.HasExtension(".txt")) { string[] Lines = FileReference.ReadAllLines(InputFile); HashSet <FileItem> DependencyItems = new HashSet <FileItem>(); foreach (string Line in Lines) { if (Line.Length > 0) { // Ignore *.tlh and *.tli files generated by the compiler from COM DLLs if (!Line.EndsWith(".tlh", StringComparison.OrdinalIgnoreCase) && !Line.EndsWith(".tli", StringComparison.OrdinalIgnoreCase)) { DependencyItems.Add(FileItem.GetItemByPath(Line)); } } } return(DependencyItems.ToList()); } else if (InputFile.HasExtension(".d")) { string Text = FileReference.ReadAllText(InputFile); List <string> Tokens = new List <string>(); StringBuilder Token = new StringBuilder(); for (int Idx = 0; TryReadMakefileToken(Text, ref Idx, Token);) { Tokens.Add(Token.ToString()); } int TokenIdx = 0; while (TokenIdx < Tokens.Count && Tokens[TokenIdx] == "\n") { TokenIdx++; } if (TokenIdx + 1 >= Tokens.Count || Tokens[TokenIdx + 1] != ":") { throw new BuildException("Unable to parse dependency file"); } TokenIdx += 2; List <FileItem> NewDependencyFiles = new List <FileItem>(); for (; TokenIdx < Tokens.Count && Tokens[TokenIdx] != "\n"; TokenIdx++) { NewDependencyFiles.Add(FileItem.GetItemByPath(Tokens[TokenIdx])); } while (TokenIdx < Tokens.Count && Tokens[TokenIdx] == "\n") { TokenIdx++; } if (TokenIdx != Tokens.Count) { throw new BuildException("Unable to parse dependency file"); } return(NewDependencyFiles); } else { throw new BuildException("Unknown dependency list file type: {0}", InputFile); } }
/// <summary> /// Determines if the file has the given extension /// </summary> /// <param name="Extension">The extension to check for</param> /// <returns>True if the file has the given extension, false otherwise</returns> public bool HasExtension(string Extension) { return(Location.HasExtension(Extension)); }
public static void WriteDocumentation(Type RulesType, FileReference OutputFile) { // Get the path to the XML documentation FileReference InputDocumentationFile = new FileReference(Assembly.GetExecutingAssembly().Location).ChangeExtension(".xml"); if (!FileReference.Exists(InputDocumentationFile)) { throw new BuildException("Generated assembly documentation not found at {0}.", InputDocumentationFile); } // Read the documentation XmlDocument InputDocumentation = new XmlDocument(); InputDocumentation.Load(InputDocumentationFile.FullName); // Filter the properties into read-only and read/write lists List <FieldInfo> ReadOnlyFields = new List <FieldInfo>(); List <FieldInfo> ReadWriteFields = new List <FieldInfo>(); foreach (FieldInfo Field in RulesType.GetFields(BindingFlags.Instance | BindingFlags.SetProperty | BindingFlags.Public)) { if (!Field.FieldType.IsClass || !Field.FieldType.Name.EndsWith("TargetRules")) { if (Field.IsInitOnly) { ReadOnlyFields.Add(Field); } else { ReadWriteFields.Add(Field); } } } // Make sure the output file is writable if (FileReference.Exists(OutputFile)) { FileReference.MakeWriteable(OutputFile); } else { DirectoryReference.CreateDirectory(OutputFile.Directory); } // Generate the documentation file if (OutputFile.HasExtension(".udn")) { WriteDocumentationUDN(OutputFile, ReadOnlyFields, ReadWriteFields, InputDocumentation); } else if (OutputFile.HasExtension(".html")) { WriteDocumentationHTML(OutputFile, ReadOnlyFields, ReadWriteFields, InputDocumentation); } else { throw new BuildException("Unable to detect format from extension of output file ({0})", OutputFile); } // Success! Log.TraceInformation("Written documentation to {0}.", OutputFile); }