* roottypes.cs: Rename from tree.cs.
[mono.git] / mcs / class / corlib / Mono.Globalization.Unicode / create-tailorings.cs
1 //
2 // It is not used to provide our collation tailoring sources, but generates
3 // easy-to-read summary of LDML tailorings for ASCII-based developers (us).
4 //
5 // The actual tailoring source is mono-tailoring-source.txt.
6 //
7
8 using System;
9 using System.Collections;
10 using System.IO;
11 using System.Globalization;
12 using System.Xml;
13 using Commons.Xml.Relaxng;
14
15 namespace Mono.Globalization.Unicode
16 {
17
18
19         class Mapping
20         {
21                 public readonly int Level;
22                 public readonly string Value;
23
24                 public Mapping (int level, string value)
25                 {
26                         Level = level;
27                         Value = value;
28                 }
29         }
30
31         public class TailoringComparer : IComparer
32         {
33                 public static TailoringComparer Instance =
34                         new TailoringComparer ();
35
36                 public int Compare (object o1, object o2)
37                 {
38                         Tailoring t1 = (Tailoring) o1;
39                         Tailoring t2 = (Tailoring) o2;
40                         return String.CompareOrdinal (t1.TargetString, t2.TargetString);
41                 }
42         }
43
44         class Tailoring
45         {
46                 public readonly int Before;
47                 string targetString;
48
49                 ArrayList tailored = new ArrayList ();
50
51                 public Tailoring (string value, int before)
52                 {
53                         targetString = value;
54                         Before = before;
55                 }
56
57                 public string TargetString {
58                         get { return targetString; }
59                 }
60
61                 public IList Tailored {
62                         get { return tailored; }
63                 }
64
65                 // <x>
66                 public void Contraction (int level, string value, string additional)
67                 {
68                         targetString += additional;
69                         tailored.Add (new Mapping (level, value));
70                 }
71
72                 // <p> <s> <t> <q> <i>
73                 public void Add (int level, string value)
74                 {
75                         tailored.Add (new Mapping (level, value));
76                 }
77
78                 // <pc> <sc> <tc> <qc> <ic>
79                 public void AddRange (int level, string value)
80                 {
81                         foreach (char c in value)
82                                 tailored.Add (new Mapping (level, new string (c, 1)));
83                 }
84
85                 public void Serialize (TextWriter w)
86                 {
87                         w.Write ("      // Target: '{0}' {{", TargetString);
88                         foreach (char c in TargetString)
89                                 w.Write ("{0:X04},", (int) c);
90                         w.WriteLine ("}} {0}",
91                                 TargetString.Length > 1 ? "!" : "");
92                         if (Before != 0)
93                                 w.WriteLine ("  // Before: {0}", Before);
94                         foreach (Mapping m in tailored) {
95                                 w.Write ("      // {0}:'{1}' {{", m.Level, m.Value);
96                                 foreach (char c in m.Value)
97                                         w.Write ("{0:X04},", (int) c);
98                                 w.WriteLine ("}");
99                         }
100                 }
101         }
102
103         public class TailoringStoreComparer : IComparer
104         {
105                 public static TailoringStoreComparer Instance =
106                         new TailoringStoreComparer ();
107
108                 public int Compare (object o1, object o2)
109                 {
110                         TailoringStore t1 = (TailoringStore) o1;
111                         TailoringStore t2 = (TailoringStore) o2;
112                         return t1.Culture.LCID - t2.Culture.LCID;
113                 }
114         }
115
116         class TailoringStore
117         {
118                 CultureInfo culture;
119                 ArrayList tailorings = new ArrayList ();
120                 string alias;
121                 bool frenchSort;
122
123                 public TailoringStore (string name)
124                 {
125                         culture = new CultureInfo (name);
126                 }
127
128                 public CultureInfo Culture {
129                         get { return culture; }
130                 }
131
132                 public bool FrenchSort {
133                         get { return frenchSort; }
134                         set { frenchSort = value; }
135                 }
136
137                 public string Alias {
138                         get { return alias; }
139                         set { alias = value; }
140                 }
141
142                 public void Add (Tailoring t)
143                 {
144                         tailorings.Add (t);
145                 }
146
147                 public int Count {
148                         get { return tailorings.Count; }
149                 }
150
151                 public void Serialize (TextWriter w)
152                 {
153                         w.WriteLine ("// Culture: {0} ({1})", culture.LCID, culture.Name);
154                         if (FrenchSort)
155                                 w.WriteLine ("// FrenchSort.");
156                         if (Alias != null)
157                                 w.WriteLine ("// Alias: {0}", Alias);
158
159                         tailorings.Sort (TailoringComparer.Instance);
160
161                         foreach (Tailoring t in tailorings)
162                                 t.Serialize (w);
163                 }
164         }
165
166         class CultureSpecificLdmlReader
167         {
168                 ArrayList ignoredFiles = new ArrayList ();
169                 ArrayList tailorings = new ArrayList ();
170
171                 public static void Main (string [] args)
172                 {
173                         new CultureSpecificLdmlReader ().Run (args);
174                 }
175
176                 void Run (string [] args)
177                 {
178                         if (args.Length < 2) {
179                                 Console.WriteLine ("specify arguments: path_to_ldml_files config_file");
180                                 return;
181                         }
182                         string dirname = args [0];
183                         string configFileName = args [1];
184                         string config = null;
185                         using (StreamReader sr = new StreamReader (configFileName)) {
186                                 config = sr.ReadToEnd ();
187                         }
188                         foreach (string configLine in config.Split ('\n')) {
189                                 int idx = configLine.IndexOf ('#');
190                                 string line = idx < 0 ? configLine : configLine.Substring (0, idx);
191                                 if (line.StartsWith ("ignore: "))
192                                         ignoredFiles.Add (line.Substring (8).Trim ());
193                         }
194
195                         XmlTextReader rng = new XmlTextReader ("ldml-limited.rng");
196                         RelaxngPattern p = RelaxngPattern.Read (rng);
197                         rng.Close ();
198
199                         foreach (FileInfo fi in new DirectoryInfo (dirname).GetFiles ("*.xml")) {
200                                 if (ignoredFiles.Contains (fi.Name))
201                                         continue; // skip
202                                 XmlTextReader inst = null;
203                                 try {
204                                         inst = new XmlTextReader (fi.FullName);
205                                         inst.XmlResolver = null;
206                                         RelaxngValidatingReader rvr = new 
207                                                 RelaxngValidatingReader (inst, p);
208                                         rvr.ReportDetails = true;
209                                         XmlDocument doc = new XmlDocument ();
210                                         doc.XmlResolver = null;
211                                         doc.Load (rvr);
212                                         TailoringStore ts = ProcessLdml (doc);
213                                         if (ts != null)
214                                                 tailorings.Add (ts);
215                                 } finally {
216                                         if (inst != null)
217                                                 inst.Close ();
218                                 }
219                         }
220
221                         tailorings.Sort (TailoringStoreComparer.Instance);
222
223                         using (TextWriter tw = new StreamWriter ("create-tailoring.out", false, System.Text.Encoding.UTF8)) {
224                                 Serialize (tw);
225                         }
226                 }
227
228                 void Serialize (TextWriter output)
229                 {
230                         output.WriteLine ("static char [] tailorings = new char [] {");
231                         foreach (TailoringStore ts in tailorings)
232                                 ts.Serialize (output);
233                         output.WriteLine ("};");
234
235                         int [] tailoringIndex = new int [0x80];
236                         int [] tailoringCount = new int [0x80];
237                         bool [] frenchSort = new bool [0x80];
238                         int current = 0;
239                         foreach (TailoringStore ts in tailorings) {
240                                 int lcid = ts.Culture.LCID;
241                                 tailoringIndex [lcid] = current;
242                                 tailoringCount [lcid] = ts.Count;
243                                 frenchSort [lcid] = ts.FrenchSort;
244                                 current += ts.Count;
245                         }
246                         // process alias
247                         foreach (TailoringStore ts in tailorings) {
248                                 if (ts.Alias == null)
249                                         continue;
250                                 int lcid = ts.Culture.LCID;
251                                 int target = new CultureInfo (ts.Alias).LCID;
252                                 tailoringIndex [lcid] = tailoringIndex [target];
253                                 tailoringCount [lcid] = tailoringCount [target];
254                                 frenchSort [lcid] = frenchSort [target];
255                         }
256
257                         output.WriteLine (@"
258 /*typedef*/ struct TailoringInfo {
259 public TailoringInfo (ushort lcid, uint idx, ushort count, bool french) { Lcid = lcid; TailoringIndex = idx; TailoringCount = count; FrenchSort = french; }
260 public readonly ushort Lcid;
261 /*guint32*/ public readonly uint TailoringIndex;
262 /*guint16*/ public readonly ushort TailoringCount;
263 /*gboolean*/ public readonly bool FrenchSort;
264 }/* TailoringInfo;*/");
265
266                         output.WriteLine ("static TailoringInfo [] tailoringIndexes = new TailoringInfo [] {");
267                         for (int i = 0; i < tailoringIndex.Length; i++)
268                                 output.WriteLine ("new TailoringInfo ({0}, {1}, {2}, {3}), ",
269                                         i,
270                                         tailoringIndex [i],
271                                         tailoringCount [i],
272                                         frenchSort [i]);
273                         output.WriteLine ("};");
274
275                         output.Flush ();
276                 }
277
278                 TailoringStore ProcessLdml (XmlDocument doc)
279                 {
280                         XmlElement langElem = doc.SelectSingleNode (
281                                 "/ldml/identity/language") as XmlElement;
282                         string lang = langElem.GetAttribute ("type");
283                         XmlElement terr = doc.SelectSingleNode (
284                                 "/ldml/identity/territory") as XmlElement;
285                         string lcid = lang + (terr != null ?
286                                 "-" + terr.GetAttribute ("type") : null);
287                         TailoringStore ts = null;
288                         try {
289                                 ts = new TailoringStore (lcid);
290                         } catch (ArgumentException) {
291                                 Console.Error.WriteLine ("WARNING: culture " + lcid + " is not supported in the runtime.");
292                                 return null;
293                         }
294 //                      Console.Error.WriteLine ("Processing " + lcid);
295
296                         XmlNode vn = doc.SelectSingleNode ("/ldml/collations/alias/@source");
297                         if (vn != null) {
298                                 ts.Alias = vn.Value;
299                                 return ts;
300                         }
301
302                         XmlElement collation = doc.SelectSingleNode ("/ldml/collations/collation[@type='standard']") as XmlElement;
303                         XmlElement settings = collation.SelectSingleNode ("settings") as XmlElement;
304                         if (settings != null)
305                                 ts.FrenchSort = settings.GetAttribute ("backwards") == "on";
306
307                         Tailoring t = null;
308                         int before = 0;
309                         string contraction = null;
310
311                         foreach (XmlNode n in collation.SelectNodes ("rules/*")) {
312                                 XmlElement el = n as XmlElement;
313                                 if (el == null)
314                                         continue;
315
316                                 switch (el.LocalName) {
317                                 case "reset":
318                                         switch (el.GetAttribute ("before")) {
319                                         case "primary": before = 1; break;
320                                         case "secondary": before = 2; break;
321                                         }
322
323                                         switch (el.FirstChild.LocalName) {
324                                         case "last_primary_ignorable":
325                                         case "last_secondary_ignorable":
326                                                 Console.Error.WriteLine ("WARNING: {0} is not supported for now.", el.FirstChild.LocalName);
327                                                 continue;
328                                         }
329                                         XmlElement cpElem = el.SelectSingleNode ("cp") as XmlElement;
330                                         string v = "";
331                                         if (cpElem != null)
332                                                 v = new string ((char) (int.Parse (
333                                                         cpElem.GetAttribute ("hex"),
334                                                         NumberStyles.HexNumber)), 1);
335                                         else
336                                                 v = el.FirstChild.Value;
337                                         t = new Tailoring (v, before);
338                                         before = 0;
339                                         contraction = null;
340                                         ts.Add (t);
341                                         break;
342                                 case "p":
343                                 case "pc":
344                                         t.Add (1, el.InnerText);
345                                         break;
346                                 case "s":
347                                 case "sc":
348                                         t.Add (2, el.InnerText);
349                                         break;
350                                 case "t":
351                                 case "tc":
352                                         t.Add (3, el.InnerText);
353                                         break;
354                                 case "q":
355                                 case "qc":
356                                         t.Add (4, el.InnerText);
357                                         break;
358                                 case "i":
359                                 case "ic":
360                                         t.Add (5, el.InnerText);
361                                         break;
362                                 case "x":
363                                         int contLevel = 0;
364                                         switch (el.FirstChild.LocalName) {
365                                         case "s":
366                                                 contLevel = 2; break;
367                                         case "t":
368                                                 contLevel = 3; break;
369                                         default:
370                                                 throw new Exception ("Not expected first child of 'x': " + el.Name);
371                                         }
372                                         if (contraction != null && el.LastChild.InnerText != contraction)
373                                                 throw new Exception ("When there are sequential 'x' elements for single tailoring, those 'extend' text must be identical.");
374                                         bool exists = contraction != null;
375                                         contraction = el.LastChild.InnerText;
376                                         t.Contraction (contLevel,
377                                                 el.FirstChild.InnerText,
378                                                 exists ? "" : contraction);
379                                         break;
380                                 default:
381                                         throw new Exception ("Support this element: " + el.Name);
382                                 }
383                         }
384                         return ts;
385                 }
386         }
387 }