Process Hacker
HeaderGen.cs
Go to the documentation of this file.
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Linq;
5 using System.Text;
6 using System.Threading.Tasks;
7 
8 namespace GenerateHeader
9 {
10  class HeaderFile
11  {
12  public string Name;
13  public List<string> Lines;
14  public List<HeaderFile> Dependencies;
15  }
16 
17  class HeaderGen
18  {
19  private string _baseDirectory;
20  private string[] _modes;
21  private string[] _files;
22  private string _outputFile;
23  private string _header = "";
24  private string _footer = "";
25 
26  private string UnEscape(string text)
27  {
28  return text.Replace("\\r", "\r").Replace("\\n", "\n").Replace("\\\\", "\\");
29  }
30 
31  public void LoadConfig(string fileName)
32  {
33  string[] lines = File.ReadAllLines(fileName);
34 
35  foreach (string line in lines)
36  {
37  string[] split = line.Split(new char[] { '=' }, 2);
38 
39  switch (split[0])
40  {
41  case "base":
42  _baseDirectory = split[1];
43  break;
44  case "modes":
45  _modes = split[1].ToLowerInvariant().Split(';');
46  break;
47  case "in":
48  _files = split[1].Split(';');
49  break;
50  case "out":
51  _outputFile = split[1];
52  break;
53  case "header":
54  _header = UnEscape(split[1]);
55  break;
56  case "footer":
57  _footer = UnEscape(split[1]);
58  break;
59  }
60  }
61  }
62 
63  private List<HeaderFile> OrderHeaderFiles(List<HeaderFile> headerFiles)
64  {
65  var result = new List<HeaderFile>();
66  var done = new HashSet<HeaderFile>();
67 
68  foreach (var h in headerFiles)
69  OrderHeaderFiles(result, done, h);
70 
71  return result;
72  }
73 
74  private void OrderHeaderFiles(List<HeaderFile> result, HashSet<HeaderFile> done, HeaderFile headerFile)
75  {
76  if (done.Contains(headerFile))
77  return;
78 
79  done.Add(headerFile);
80 
81  foreach (var h in headerFile.Dependencies)
82  OrderHeaderFiles(result, done, h);
83 
84  result.Add(headerFile);
85  }
86 
87  private List<string> ProcessHeaderLines(IEnumerable<string> lines)
88  {
89  var result = new List<string>();
90  var modes = new HashSet<string>();
91  var blankLine = false;
92 
93  foreach (var line in lines)
94  {
95  var s = line.Trim();
96 
97  if (s.StartsWith("// begin_"))
98  {
99  modes.Add(s.Remove(0, "// begin_".Length));
100  }
101  else if (s.StartsWith("// end_"))
102  {
103  modes.Remove(s.Remove(0, "// end_".Length));
104  }
105  else
106  {
107  bool blockMode = _modes.Any(modes.Contains);
108  bool lineMode = _modes.Any(mode =>
109  {
110  int indexOfMarker = s.LastIndexOf("// " + mode);
111  if (indexOfMarker == -1)
112  return false;
113 
114  return s.Substring(indexOfMarker).Trim().All(c => char.IsLetterOrDigit(c) || c == ' ' || c == '/');
115  });
116 
117  if (blockMode || lineMode)
118  {
119  if (blankLine && result.Count != 0)
120  result.Add(string.Empty);
121 
122  result.Add(line);
123  blankLine = false;
124  }
125  else if (s.Length == 0)
126  {
127  blankLine = true;
128  }
129  }
130  }
131 
132  return result;
133  }
134 
135  public void Execute()
136  {
137  // Read in all header files.
138 
139  var headerFiles = _files.Select(fileName =>
140  {
141  var fullFileName = _baseDirectory + "\\" + fileName;
142  var lines = File.ReadAllLines(fullFileName).ToList();
143 
144  return new HeaderFile { Name = Path.GetFileName(fullFileName).ToLowerInvariant(), Lines = lines };
145  }).ToDictionary(h => h.Name);
146 
147  foreach (var h in headerFiles.Values)
148  {
149  var partitions =
150  h.Lines
151  .Select(s =>
152  {
153  var trimmed = s.Trim().ToLowerInvariant();
154  if (trimmed.StartsWith("#include <") && trimmed.EndsWith(">"))
155  {
156  HeaderFile d;
157  if (headerFiles.TryGetValue(trimmed.Remove(trimmed.Length - 1).Remove(0, "#include <".Length), out d))
158  return Tuple.Create(s, d);
159  else
160  return Tuple.Create<string, HeaderFile>(s, null);
161  }
162  return Tuple.Create<string, HeaderFile>(s, null);
163  })
164  .ToLookup(p => p.Item2 != null);
165 
166  h.Lines = partitions[false].Select(p => p.Item1).ToList();
167  h.Dependencies = partitions[true].Select(p => p.Item2).Distinct().ToList();
168 
169  foreach (var d in h.Dependencies)
170  Console.WriteLine("Dependency: " + h.Name + " -> " + d.Name);
171  }
172 
173  // Generate the ordering.
174 
175  var orderedHeaderFiles = OrderHeaderFiles(_files.Select(s => headerFiles[Path.GetFileName(s).ToLower()]).ToList());
176 
177  // Process each header file and remove irrelevant content.
178 
179  foreach (var h in orderedHeaderFiles)
180  h.Lines = ProcessHeaderLines(h.Lines);
181 
182  // Write out the result.
183 
184  StreamWriter sw = new StreamWriter(_baseDirectory + "\\" + _outputFile);
185 
186  // Header
187 
188  sw.Write(_header);
189 
190  // Header files
191 
192  foreach (var h in orderedHeaderFiles)
193  {
194  Console.WriteLine("Header file: " + h.Name);
195 
196  sw.WriteLine();
197  sw.WriteLine("//");
198  sw.WriteLine("// " + Path.GetFileNameWithoutExtension(h.Name));
199  sw.WriteLine("//");
200  sw.WriteLine();
201 
202  foreach (var line in h.Lines)
203  sw.WriteLine(line);
204  }
205 
206  // Footer
207 
208  sw.Write(_footer);
209 
210  sw.Close();
211  }
212  }
213 }