aboutsummaryrefslogtreecommitdiff
path: root/src/MessagesToMessages/Program.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/MessagesToMessages/Program.cs')
-rw-r--r--src/MessagesToMessages/Program.cs237
1 files changed, 237 insertions, 0 deletions
diff --git a/src/MessagesToMessages/Program.cs b/src/MessagesToMessages/Program.cs
new file mode 100644
index 00000000..514c8a26
--- /dev/null
+++ b/src/MessagesToMessages/Program.cs
@@ -0,0 +1,237 @@
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Linq;
5using System.Text;
6using System.Xml.Linq;
7
8namespace MessagesToMessages
9{
10 class Program
11 {
12 static readonly XNamespace ns = "http://schemas.microsoft.com/genmsgs/2004/07/messages";
13 static readonly XName ClassDefinition = ns + "Class";
14 static readonly XName MessageDefinition = ns + "Message";
15 static readonly XName InstanceDefinition = ns + "Instance";
16 static readonly XName ParameterDefinition = ns + "Parameter";
17 static readonly XName Id = "Id";
18 static readonly XName Level = "Level";
19 static readonly XName Number = "Number";
20 static readonly XName SourceLineNumbers = "SourceLineNumbers";
21 static readonly XName Type = "Type";
22 static readonly XName Name = "Name";
23
24 static void Main(string[] args)
25 {
26 if (args.Length == 0)
27 {
28 return;
29 }
30 else if (args.Length < 2)
31 {
32 Console.WriteLine("Need to specify output folder as well.");
33 }
34 else if (!Directory.Exists(args[1]))
35 {
36 Console.WriteLine("Output folder does not exist: {0}", args[1]);
37 }
38
39 var messages = ReadXml(Path.GetFullPath(args[0]));
40
41 foreach (var m in messages.GroupBy(m => m.Level))
42 {
43 var result = GenerateCs(m.Key, m);
44
45 var path = Path.Combine(args[1], m.Key + "Messages.cs");
46 File.WriteAllText(path, result);
47 }
48 }
49
50 private static IEnumerable<Message> ReadXml(string inputPath)
51 {
52 var doc = XDocument.Load(inputPath);
53
54 foreach (var xClass in doc.Root.Descendants(ClassDefinition))
55 {
56 var level = xClass.Attribute(Level).Value;
57
58 var unique = new HashSet<string>();
59 var lastNumber = 0;
60 foreach (var xMessage in xClass.Elements(MessageDefinition))
61 {
62 var id = xMessage.Attribute(Id).Value;
63
64 if (!unique.Add(id))
65 {
66 Console.WriteLine("Duplicated message: {0}", id);
67 }
68
69 if (!Int32.TryParse(xMessage.Attribute(Number)?.Value, out var number))
70 {
71 number = lastNumber;
72 }
73 lastNumber = number + 1;
74
75 var sln = xMessage.Attribute(SourceLineNumbers)?.Value != "no";
76
77 var suffix = 0;
78 foreach (var xInstance in xMessage.Elements(InstanceDefinition))
79 {
80 var value = xInstance.Value.Trim();
81
82 var parameters = xInstance.Elements(ParameterDefinition).Select(ReadParameter).ToList();
83
84 yield return new Message { Id = id, Level = level, Number = number, Parameters = parameters, SourceLineNumbers = sln, Value = value, Suffix = suffix == 0 ? String.Empty : suffix.ToString() };
85
86 ++suffix;
87 }
88 }
89 }
90 }
91
92 private static Parameter ReadParameter(XElement element)
93 {
94 var name = element.Attribute(Name)?.Value;
95 var type = element.Attribute(Type)?.Value ?? "string";
96
97 if (type.StartsWith("System."))
98 {
99 type = type.Substring(7);
100 }
101
102 switch (type)
103 {
104 case "String":
105 type = "string";
106 break;
107
108 case "Int32":
109 type = "int";
110 break;
111
112 case "Int64":
113 type = "long";
114 break;
115 }
116
117 return new Parameter { Name = name, Type = type };
118 }
119
120 private static string GenerateCs(string level, IEnumerable<Message> messages)
121 {
122 var header = String.Join(Environment.NewLine,
123 "// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.",
124 "",
125 "namespace WixToolset.Data",
126 "{",
127 " using System;",
128 " using System.Resources;",
129 "",
130 " public static class {0}Messages",
131 " {");
132
133 var messageFormat = String.Join(Environment.NewLine,
134 " public static Message {0}({1})",
135 " {{",
136 " return Message({4}, Ids.{0}, \"{3}\"{2});",
137 " }}",
138 "");
139
140
141 var endMessagesFormat = String.Join(Environment.NewLine,
142 " private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args)",
143 " {{",
144 " return new Message(sourceLineNumber, MessageLevel.{0}, (int)id, format, args);",
145 " }}",
146 "",
147 " private static Message Message(SourceLineNumber sourceLineNumber, Ids id, ResourceManager resourceManager, string resourceName, params object[] args)",
148 " {{",
149 " return new Message(sourceLineNumber, MessageLevel.{0}, (int)id, resourceManager, resourceName, args);",
150 " }}",
151 "",
152 " public enum Ids",
153 " {{");
154
155 var idEnumFormat =
156 " {0} = {1},";
157 var footer = String.Join(Environment.NewLine,
158 " }",
159 " }",
160 "}",
161 "");
162
163 var sb = new StringBuilder();
164
165 sb.AppendLine(header.Replace("{0}", level));
166
167 foreach (var message in messages.OrderBy(m => m.Id))
168 {
169 var paramsWithTypes = String.Join(", ", message.Parameters.Select(p => $"{p.Type} {p.Name}"));
170 var paramsWithoutTypes = String.Join(", ", message.Parameters.Select(p => p.Name));
171
172 if (message.SourceLineNumbers)
173 {
174 paramsWithTypes = String.IsNullOrEmpty(paramsWithTypes)
175 ? "SourceLineNumber sourceLineNumbers"
176 : "SourceLineNumber sourceLineNumbers, " + paramsWithTypes;
177 }
178
179 if (!String.IsNullOrEmpty(paramsWithoutTypes))
180 {
181 paramsWithoutTypes = ", " + paramsWithoutTypes;
182 }
183
184 sb.AppendFormat(messageFormat, message.Id, paramsWithTypes, paramsWithoutTypes, ToCSharpString(message.Value), message.SourceLineNumbers ? "sourceLineNumbers" : "null");
185
186 sb.AppendLine();
187 }
188
189 sb.AppendFormat(endMessagesFormat, level);
190 sb.AppendLine();
191
192 var unique = new HashSet<int>();
193 foreach (var message in messages.OrderBy(m => m.Number))
194 {
195 if (unique.Add(message.Number))
196 {
197 sb.AppendFormat(idEnumFormat, message.Id, message.Number);
198 sb.AppendLine();
199 }
200 }
201
202 sb.Append(footer);
203
204 return sb.ToString();
205 }
206
207 private static string ToCSharpString(string value)
208 {
209 return value.Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\r", "\\r").Replace("\n", "\\n").Replace("\t", "\\t");
210 }
211
212 private class Message
213 {
214 public string Id { get; set; }
215
216 public string Suffix { get; set; }
217
218 public string Level { get; set; }
219
220 public int Number { get; set; }
221
222 public bool SourceLineNumbers { get; set; }
223
224 public string Value { get; set; }
225
226 public IEnumerable<Parameter> Parameters { get; set; }
227 }
228
229
230 private class Parameter
231 {
232 public string Name { get; set; }
233
234 public string Type { get; set; }
235 }
236 }
237}