aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Prebuild/src/Core/Parse/Preprocessor.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Prebuild/src/Core/Parse/Preprocessor.cs')
-rw-r--r--Prebuild/src/Core/Parse/Preprocessor.cs1088
1 files changed, 544 insertions, 544 deletions
diff --git a/Prebuild/src/Core/Parse/Preprocessor.cs b/Prebuild/src/Core/Parse/Preprocessor.cs
index 0cd6e82..0648fad 100644
--- a/Prebuild/src/Core/Parse/Preprocessor.cs
+++ b/Prebuild/src/Core/Parse/Preprocessor.cs
@@ -5,16 +5,16 @@ Copyright (c) 2004-2005 Matthew Holmes (matthew@wildfiregames.com), Dan Moorehea
5Redistribution and use in source and binary forms, with or without modification, are permitted 5Redistribution and use in source and binary forms, with or without modification, are permitted
6provided that the following conditions are met: 6provided that the following conditions are met:
7 7
8* Redistributions of source code must retain the above copyright notice, this list of conditions 8* Redistributions of source code must retain the above copyright notice, this list of conditions
9 and the following disclaimer. 9 and the following disclaimer.
10* Redistributions in binary form must reproduce the above copyright notice, this list of conditions 10* Redistributions in binary form must reproduce the above copyright notice, this list of conditions
11 and the following disclaimer in the documentation and/or other materials provided with the 11 and the following disclaimer in the documentation and/or other materials provided with the
12 distribution. 12 distribution.
13* The name of the author may not be used to endorse or promote products derived from this software 13* The name of the author may not be used to endorse or promote products derived from this software
14 without specific prior written permission. 14 without specific prior written permission.
15 15
16THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 16THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
17BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 20OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
@@ -31,336 +31,336 @@ using System.Xml;
31 31
32namespace Prebuild.Core.Parse 32namespace Prebuild.Core.Parse
33{ 33{
34 /// <summary> 34 /// <summary>
35 /// 35 ///
36 /// </summary> 36 /// </summary>
37 public enum OperatorSymbol 37 public enum OperatorSymbol
38 { 38 {
39 /// <summary> 39 /// <summary>
40 /// 40 ///
41 /// </summary> 41 /// </summary>
42 None, 42 None,
43 /// <summary> 43 /// <summary>
44 /// 44 ///
45 /// </summary> 45 /// </summary>
46 Equal, 46 Equal,
47 /// <summary> 47 /// <summary>
48 /// 48 ///
49 /// </summary> 49 /// </summary>
50 NotEqual, 50 NotEqual,
51 /// <summary> 51 /// <summary>
52 /// 52 ///
53 /// </summary> 53 /// </summary>
54 LessThan, 54 LessThan,
55 /// <summary> 55 /// <summary>
56 /// 56 ///
57 /// </summary> 57 /// </summary>
58 GreaterThan, 58 GreaterThan,
59 /// <summary> 59 /// <summary>
60 /// 60 ///
61 /// </summary> 61 /// </summary>
62 LessThanEqual, 62 LessThanEqual,
63 /// <summary> 63 /// <summary>
64 /// 64 ///
65 /// </summary> 65 /// </summary>
66 GreaterThanEqual 66 GreaterThanEqual
67 } 67 }
68 68
69 /// <summary> 69 /// <summary>
70 /// 70 ///
71 /// </summary> 71 /// </summary>
72 public class Preprocessor 72 public class Preprocessor
73 { 73 {
74 #region Constants 74 #region Constants
75 75
76 /// <summary> 76 /// <summary>
77 /// Includes the regex to look for file tags in the <?include 77 /// Includes the regex to look for file tags in the <?include
78 /// ?> processing instruction. 78 /// ?> processing instruction.
79 /// </summary> 79 /// </summary>
80 private static readonly Regex includeFileRegex = new Regex("file=\"(.+?)\""); 80 private static readonly Regex includeFileRegex = new Regex("file=\"(.+?)\"");
81 81
82 #endregion 82 #endregion
83 83
84 #region Fields 84 #region Fields
85 85
86 readonly XmlDocument m_OutDoc = new XmlDocument(); 86 readonly XmlDocument m_OutDoc = new XmlDocument();
87 readonly Stack<IfContext> m_IfStack = new Stack<IfContext>(); 87 readonly Stack<IfContext> m_IfStack = new Stack<IfContext>();
88 readonly Dictionary<string, object> m_Variables = new Dictionary<string, object>(); 88 readonly Dictionary<string, object> m_Variables = new Dictionary<string, object>();
89 89
90 #endregion 90 #endregion
91 91
92 #region Constructors 92 #region Constructors
93 93
94 /// <summary> 94 /// <summary>
95 /// Initializes a new instance of the <see cref="Preprocessor"/> class. 95 /// Initializes a new instance of the <see cref="Preprocessor"/> class.
96 /// </summary> 96 /// </summary>
97 public Preprocessor() 97 public Preprocessor()
98 { 98 {
99 RegisterVariable("OS", GetOS()); 99 RegisterVariable("OS", GetOS());
100 RegisterVariable("RuntimeVersion", Environment.Version.Major); 100 RegisterVariable("RuntimeVersion", Environment.Version.Major);
101 RegisterVariable("RuntimeMajor", Environment.Version.Major); 101 RegisterVariable("RuntimeMajor", Environment.Version.Major);
102 RegisterVariable("RuntimeMinor", Environment.Version.Minor); 102 RegisterVariable("RuntimeMinor", Environment.Version.Minor);
103 RegisterVariable("RuntimeRevision", Environment.Version.Revision); 103 RegisterVariable("RuntimeRevision", Environment.Version.Revision);
104 } 104 }
105 105
106 #endregion 106 #endregion
107 107
108 #region Properties 108 #region Properties
109 109
110 /// <summary> 110 /// <summary>
111 /// Gets the processed doc. 111 /// Gets the processed doc.
112 /// </summary> 112 /// </summary>
113 /// <value>The processed doc.</value> 113 /// <value>The processed doc.</value>
114 public XmlDocument ProcessedDoc 114 public XmlDocument ProcessedDoc
115 { 115 {
116 get 116 get
117 { 117 {
118 return m_OutDoc; 118 return m_OutDoc;
119 } 119 }
120 } 120 }
121 121
122 #endregion 122 #endregion
123 123
124 #region Private Methods 124 #region Private Methods
125 125
126 /// <summary> 126 /// <summary>
127 /// Parts of this code were taken from NAnt and is subject to the GPL 127 /// Parts of this code were taken from NAnt and is subject to the GPL
128 /// as per NAnt's license. Thanks to the NAnt guys for this little gem. 128 /// as per NAnt's license. Thanks to the NAnt guys for this little gem.
129 /// </summary> 129 /// </summary>
130 /// <returns></returns> 130 /// <returns></returns>
131 public static string GetOS() 131 public static string GetOS()
132 { 132 {
133 PlatformID platId = Environment.OSVersion.Platform; 133 PlatformID platId = Environment.OSVersion.Platform;
134 if(platId == PlatformID.Win32NT || platId == PlatformID.Win32Windows) 134 if(platId == PlatformID.Win32NT || platId == PlatformID.Win32Windows)
135 { 135 {
136 return "Win32"; 136 return "Win32";
137 } 137 }
138 138
139 if (File.Exists("/System/Library/Frameworks/Cocoa.framework/Cocoa")) 139 if (File.Exists("/System/Library/Frameworks/Cocoa.framework/Cocoa"))
140 { 140 {
141 return "MACOSX"; 141 return "MACOSX";
142 } 142 }
143 143
144 /* 144 /*
145 * .NET 1.x, under Mono, the UNIX code is 128. Under 145 * .NET 1.x, under Mono, the UNIX code is 128. Under
146 * .NET 2.x, Mono or MS, the UNIX code is 4 146 * .NET 2.x, Mono or MS, the UNIX code is 4
147 */ 147 */
148 if(Environment.Version.Major == 1) 148 if(Environment.Version.Major == 1)
149 { 149 {
150 if((int)platId == 128) 150 if((int)platId == 128)
151 { 151 {
152 return "UNIX"; 152 return "UNIX";
153 } 153 }
154 } 154 }
155 else if((int)platId == 4) 155 else if((int)platId == 4)
156 { 156 {
157 return "UNIX"; 157 return "UNIX";
158 } 158 }
159 159
160 return "Unknown"; 160 return "Unknown";
161 } 161 }
162 162
163 private static bool CompareNum(OperatorSymbol oper, int val1, int val2) 163 private static bool CompareNum(OperatorSymbol oper, int val1, int val2)
164 { 164 {
165 switch(oper) 165 switch(oper)
166 { 166 {
167 case OperatorSymbol.Equal: 167 case OperatorSymbol.Equal:
168 return (val1 == val2); 168 return (val1 == val2);
169 case OperatorSymbol.NotEqual: 169 case OperatorSymbol.NotEqual:
170 return (val1 != val2); 170 return (val1 != val2);
171 case OperatorSymbol.LessThan: 171 case OperatorSymbol.LessThan:
172 return (val1 < val2); 172 return (val1 < val2);
173 case OperatorSymbol.LessThanEqual: 173 case OperatorSymbol.LessThanEqual:
174 return (val1 <= val2); 174 return (val1 <= val2);
175 case OperatorSymbol.GreaterThan: 175 case OperatorSymbol.GreaterThan:
176 return (val1 > val2); 176 return (val1 > val2);
177 case OperatorSymbol.GreaterThanEqual: 177 case OperatorSymbol.GreaterThanEqual:
178 return (val1 >= val2); 178 return (val1 >= val2);
179 } 179 }
180 180
181 throw new WarningException("Unknown operator type"); 181 throw new WarningException("Unknown operator type");
182 } 182 }
183 183
184 private static bool CompareStr(OperatorSymbol oper, string val1, string val2) 184 private static bool CompareStr(OperatorSymbol oper, string val1, string val2)
185 { 185 {
186 switch(oper) 186 switch(oper)
187 { 187 {
188 case OperatorSymbol.Equal: 188 case OperatorSymbol.Equal:
189 return (val1 == val2); 189 return (val1 == val2);
190 case OperatorSymbol.NotEqual: 190 case OperatorSymbol.NotEqual:
191 return (val1 != val2); 191 return (val1 != val2);
192 case OperatorSymbol.LessThan: 192 case OperatorSymbol.LessThan:
193 return (val1.CompareTo(val2) < 0); 193 return (val1.CompareTo(val2) < 0);
194 case OperatorSymbol.LessThanEqual: 194 case OperatorSymbol.LessThanEqual:
195 return (val1.CompareTo(val2) <= 0); 195 return (val1.CompareTo(val2) <= 0);
196 case OperatorSymbol.GreaterThan: 196 case OperatorSymbol.GreaterThan:
197 return (val1.CompareTo(val2) > 0); 197 return (val1.CompareTo(val2) > 0);
198 case OperatorSymbol.GreaterThanEqual: 198 case OperatorSymbol.GreaterThanEqual:
199 return (val1.CompareTo(val2) >= 0); 199 return (val1.CompareTo(val2) >= 0);
200 } 200 }
201 201
202 throw new WarningException("Unknown operator type"); 202 throw new WarningException("Unknown operator type");
203 } 203 }
204 204
205 private static char NextChar(int idx, string str) 205 private static char NextChar(int idx, string str)
206 { 206 {
207 if((idx + 1) >= str.Length) 207 if((idx + 1) >= str.Length)
208 { 208 {
209 return Char.MaxValue; 209 return Char.MaxValue;
210 } 210 }
211 211
212 return str[idx + 1]; 212 return str[idx + 1];
213 } 213 }
214 // Very very simple expression parser. Can only match expressions of the form 214 // Very very simple expression parser. Can only match expressions of the form
215 // <var> <op> <value>: 215 // <var> <op> <value>:
216 // OS = Windows 216 // OS = Windows
217 // OS != Linux 217 // OS != Linux
218 // RuntimeMinor > 0 218 // RuntimeMinor > 0
219 private bool ParseExpression(string exp) 219 private bool ParseExpression(string exp)
220 { 220 {
221 if(exp == null) 221 if(exp == null)
222 { 222 {
223 throw new ArgumentException("Invalid expression, cannot be null"); 223 throw new ArgumentException("Invalid expression, cannot be null");
224 } 224 }
225 225
226 exp = exp.Trim(); 226 exp = exp.Trim();
227 if(exp.Length < 1) 227 if(exp.Length < 1)
228 { 228 {
229 throw new ArgumentException("Invalid expression, cannot be 0 length"); 229 throw new ArgumentException("Invalid expression, cannot be 0 length");
230 } 230 }
231 231
232 string id = ""; 232 string id = "";
233 string str = ""; 233 string str = "";
234 OperatorSymbol oper = OperatorSymbol.None; 234 OperatorSymbol oper = OperatorSymbol.None;
235 bool inStr = false; 235 bool inStr = false;
236 236
237 for(int i = 0; i < exp.Length; i++) 237 for(int i = 0; i < exp.Length; i++)
238 { 238 {
239 char c = exp[i]; 239 char c = exp[i];
240 if(Char.IsWhiteSpace(c)) 240 if(Char.IsWhiteSpace(c))
241 { 241 {
242 continue; 242 continue;
243 } 243 }
244 244
245 if(Char.IsLetterOrDigit(c) || c == '_') 245 if(Char.IsLetterOrDigit(c) || c == '_')
246 { 246 {
247 if(inStr) 247 if(inStr)
248 { 248 {
249 str += c; 249 str += c;
250 } 250 }
251 else 251 else
252 { 252 {
253 id += c; 253 id += c;
254 } 254 }
255 } 255 }
256 else if(c == '\"') 256 else if(c == '\"')
257 { 257 {
258 inStr = !inStr; 258 inStr = !inStr;
259 if(inStr) 259 if(inStr)
260 { 260 {
261 str = ""; 261 str = "";
262 } 262 }
263 } 263 }
264 else 264 else
265 { 265 {
266 if(inStr) 266 if(inStr)
267 { 267 {
268 str += c; 268 str += c;
269 } 269 }
270 else 270 else
271 { 271 {
272 switch(c) 272 switch(c)
273 { 273 {
274 case '=': 274 case '=':
275 oper = OperatorSymbol.Equal; 275 oper = OperatorSymbol.Equal;
276 break; 276 break;
277 277
278 case '!': 278 case '!':
279 if(NextChar(i, exp) == '=') 279 if(NextChar(i, exp) == '=')
280 { 280 {
281 oper = OperatorSymbol.NotEqual; 281 oper = OperatorSymbol.NotEqual;
282 } 282 }
283 283
284 break; 284 break;
285 285
286 case '<': 286 case '<':
287 if(NextChar(i, exp) == '=') 287 if(NextChar(i, exp) == '=')
288 { 288 {
289 oper = OperatorSymbol.LessThanEqual; 289 oper = OperatorSymbol.LessThanEqual;
290 } 290 }
291 else 291 else
292 { 292 {
293 oper = OperatorSymbol.LessThan; 293 oper = OperatorSymbol.LessThan;
294 } 294 }
295 295
296 break; 296 break;
297 297
298 case '>': 298 case '>':
299 if(NextChar(i, exp) == '=') 299 if(NextChar(i, exp) == '=')
300 { 300 {
301 oper = OperatorSymbol.GreaterThanEqual; 301 oper = OperatorSymbol.GreaterThanEqual;
302 } 302 }
303 else 303 else
304 { 304 {
305 oper = OperatorSymbol.GreaterThan; 305 oper = OperatorSymbol.GreaterThan;
306 } 306 }
307 307
308 break; 308 break;
309 } 309 }
310 } 310 }
311 } 311 }
312 } 312 }
313 313
314 314
315 if(inStr) 315 if(inStr)
316 { 316 {
317 throw new WarningException("Expected end of string in expression"); 317 throw new WarningException("Expected end of string in expression");
318 } 318 }
319 319
320 if(oper == OperatorSymbol.None) 320 if(oper == OperatorSymbol.None)
321 { 321 {
322 throw new WarningException("Expected operator in expression"); 322 throw new WarningException("Expected operator in expression");
323 } 323 }
324 if(id.Length < 1) 324 if(id.Length < 1)
325 { 325 {
326 throw new WarningException("Expected identifier in expression"); 326 throw new WarningException("Expected identifier in expression");
327 } 327 }
328 if(str.Length < 1) 328 if(str.Length < 1)
329 { 329 {
330 throw new WarningException("Expected value in expression"); 330 throw new WarningException("Expected value in expression");
331 } 331 }
332 332
333 bool ret; 333 bool ret;
334 try 334 try
335 { 335 {
336 object val = m_Variables[id.ToLower()]; 336 object val = m_Variables[id.ToLower()];
337 if(val == null) 337 if(val == null)
338 { 338 {
339 throw new WarningException("Unknown identifier '{0}'", id); 339 throw new WarningException("Unknown identifier '{0}'", id);
340 } 340 }
341 341
342 Type t = val.GetType(); 342 Type t = val.GetType();
343 if(t.IsAssignableFrom(typeof(int))) 343 if(t.IsAssignableFrom(typeof(int)))
344 { 344 {
345 int numVal = (int)val; 345 int numVal = (int)val;
346 int numVal2 = Int32.Parse(str); 346 int numVal2 = Int32.Parse(str);
347 ret = CompareNum(oper, numVal, numVal2); 347 ret = CompareNum(oper, numVal, numVal2);
348 } 348 }
349 else 349 else
350 { 350 {
351 string strVal = val.ToString(); 351 string strVal = val.ToString();
352 string strVal2 = str; 352 string strVal2 = str;
353 ret = CompareStr(oper, strVal, strVal2); 353 ret = CompareStr(oper, strVal, strVal2);
354 } 354 }
355 } 355 }
356 catch(ArgumentException ex) 356 catch(ArgumentException ex)
357 { 357 {
358 ex.ToString(); 358 ex.ToString();
359 throw new WarningException("Invalid value type for system variable '{0}', expected int", id); 359 throw new WarningException("Invalid value type for system variable '{0}', expected int", id);
360 } 360 }
361 361
362 return ret; 362 return ret;
363 } 363 }
364 364
365 /// <summary> 365 /// <summary>
366 /// Taken from current Prebuild included in OpenSim 0.7.x 366 /// Taken from current Prebuild included in OpenSim 0.7.x
@@ -376,13 +376,13 @@ namespace Prebuild.Core.Parse
376 if (!include.Contains ("*")) { 376 if (!include.Contains ("*")) {
377 return; 377 return;
378 } 378 }
379 379
380 // Console.WriteLine("Processing {0}", include); 380 // Console.WriteLine("Processing {0}", include);
381 381
382 // Break up the include into pre and post wildcard sections 382 // Break up the include into pre and post wildcard sections
383 string preWildcard = include.Substring (0, include.IndexOf ("*")); 383 string preWildcard = include.Substring (0, include.IndexOf ("*"));
384 string postWildcard = include.Substring (include.IndexOf ("*") + 2); 384 string postWildcard = include.Substring (include.IndexOf ("*") + 2);
385 385
386 // If preWildcard is a directory, recurse 386 // If preWildcard is a directory, recurse
387 if (Directory.Exists (preWildcard)) { 387 if (Directory.Exists (preWildcard)) {
388 string[] directories = Directory.GetDirectories (preWildcard); 388 string[] directories = Directory.GetDirectories (preWildcard);
@@ -390,7 +390,7 @@ namespace Prebuild.Core.Parse
390 Array.Reverse (directories); 390 Array.Reverse (directories);
391 foreach (string dirPath in directories) { 391 foreach (string dirPath in directories) {
392 //Console.WriteLine ("Scanning : {0}", dirPath); 392 //Console.WriteLine ("Scanning : {0}", dirPath);
393 393
394 string includeFile = Path.Combine (dirPath, postWildcard); 394 string includeFile = Path.Combine (dirPath, postWildcard);
395 if (includeFile.Contains ("*")) { 395 if (includeFile.Contains ("*")) {
396 // postWildcard included another wildcard, recurse. 396 // postWildcard included another wildcard, recurse.
@@ -408,10 +408,10 @@ namespace Prebuild.Core.Parse
408 // preWildcard is not a path to a directory, so the wildcard is in the filename 408 // preWildcard is not a path to a directory, so the wildcard is in the filename
409 string searchFilename = Path.GetFileName (preWildcard.Substring (preWildcard.IndexOf ("/") + 1) + "*" + postWildcard); 409 string searchFilename = Path.GetFileName (preWildcard.Substring (preWildcard.IndexOf ("/") + 1) + "*" + postWildcard);
410 Console.WriteLine ("searchFilename: {0}", searchFilename); 410 Console.WriteLine ("searchFilename: {0}", searchFilename);
411 411
412 string searchDirectory = Path.GetDirectoryName (preWildcard); 412 string searchDirectory = Path.GetDirectoryName (preWildcard);
413 Console.WriteLine ("searchDirectory: {0}", searchDirectory); 413 Console.WriteLine ("searchDirectory: {0}", searchDirectory);
414 414
415 string[] files = Directory.GetFiles (searchDirectory, searchFilename); 415 string[] files = Directory.GetFiles (searchDirectory, searchFilename);
416 Array.Sort (files); 416 Array.Sort (files);
417 Array.Reverse (files); 417 Array.Reverse (files);
@@ -426,227 +426,227 @@ namespace Prebuild.Core.Parse
426 } 426 }
427 } 427 }
428 428
429 #endregion 429 #endregion
430 430
431 #region Public Methods 431 #region Public Methods
432 432
433 /// <summary> 433 /// <summary>
434 /// 434 ///
435 /// </summary> 435 /// </summary>
436 /// <param name="name"></param> 436 /// <param name="name"></param>
437 /// <param name="variableValue"></param> 437 /// <param name="variableValue"></param>
438 public void RegisterVariable(string name, object variableValue) 438 public void RegisterVariable(string name, object variableValue)
439 { 439 {
440 if(name == null || variableValue == null) 440 if(name == null || variableValue == null)
441 { 441 {
442 return; 442 return;
443 } 443 }
444 444
445 m_Variables[name.ToLower()] = variableValue; 445 m_Variables[name.ToLower()] = variableValue;
446 } 446 }
447 447
448 /// <summary> 448 /// <summary>
449 /// Performs validation on the xml source as well as evaluates conditional and flow expresions 449 /// Performs validation on the xml source as well as evaluates conditional and flow expresions
450 /// </summary> 450 /// </summary>
451 /// <exception cref="ArgumentException">For invalid use of conditional expressions or for invalid XML syntax. If a XmlValidatingReader is passed, then will also throw exceptions for non-schema-conforming xml</exception> 451 /// <exception cref="ArgumentException">For invalid use of conditional expressions or for invalid XML syntax. If a XmlValidatingReader is passed, then will also throw exceptions for non-schema-conforming xml</exception>
452 /// <param name="initialReader"></param> 452 /// <param name="initialReader"></param>
453 /// <returns>the output xml </returns> 453 /// <returns>the output xml </returns>
454 public string Process(XmlReader initialReader) 454 public string Process(XmlReader initialReader)
455 { 455 {
456 if(initialReader == null) 456 if(initialReader == null)
457 { 457 {
458 throw new ArgumentException("Invalid XML reader to pre-process"); 458 throw new ArgumentException("Invalid XML reader to pre-process");
459 } 459 }
460 460
461 IfContext context = new IfContext(true, true, IfState.None); 461 IfContext context = new IfContext(true, true, IfState.None);
462 StringWriter xmlText = new StringWriter(); 462 StringWriter xmlText = new StringWriter();
463 XmlTextWriter writer = new XmlTextWriter(xmlText); 463 XmlTextWriter writer = new XmlTextWriter(xmlText);
464 writer.Formatting = Formatting.Indented; 464 writer.Formatting = Formatting.Indented;
465 465
466 // Create a queue of XML readers and add the initial 466 // Create a queue of XML readers and add the initial
467 // reader to it. Then we process until we run out of 467 // reader to it. Then we process until we run out of
468 // readers which lets the <?include?> operation add more 468 // readers which lets the <?include?> operation add more
469 // readers to generate a multi-file parser and not require 469 // readers to generate a multi-file parser and not require
470 // XML fragments that a recursive version would use. 470 // XML fragments that a recursive version would use.
471 Stack<XmlReader> readerStack = new Stack<XmlReader>(); 471 Stack<XmlReader> readerStack = new Stack<XmlReader>();
472 readerStack.Push(initialReader); 472 readerStack.Push(initialReader);
473 473
474 while(readerStack.Count > 0) 474 while(readerStack.Count > 0)
475 { 475 {
476 // Pop off the next reader. 476 // Pop off the next reader.
477 XmlReader reader = readerStack.Pop(); 477 XmlReader reader = readerStack.Pop();
478 478
479 // Process through this XML reader until it is 479 // Process through this XML reader until it is
480 // completed (or it is replaced by the include 480 // completed (or it is replaced by the include
481 // operation). 481 // operation).
482 while(reader.Read()) 482 while(reader.Read())
483 { 483 {
484 // The prebuild file has a series of processing 484 // The prebuild file has a series of processing
485 // instructions which allow for specific 485 // instructions which allow for specific
486 // inclusions based on operating system or to 486 // inclusions based on operating system or to
487 // include additional files. 487 // include additional files.
488 if(reader.NodeType == XmlNodeType.ProcessingInstruction) 488 if(reader.NodeType == XmlNodeType.ProcessingInstruction)
489 { 489 {
490 bool ignore = false; 490 bool ignore = false;
491 491
492 switch(reader.LocalName) 492 switch(reader.LocalName)
493 { 493 {
494 case "include": 494 case "include":
495 // use regular expressions to parse out the attributes. 495 // use regular expressions to parse out the attributes.
496 MatchCollection matches = includeFileRegex.Matches(reader.Value); 496 MatchCollection matches = includeFileRegex.Matches(reader.Value);
497 497
498 // make sure there is only one file attribute. 498 // make sure there is only one file attribute.
499 if(matches.Count > 1) 499 if(matches.Count > 1)
500 { 500 {
501 throw new WarningException("An <?include ?> node was found, but it specified more than one file."); 501 throw new WarningException("An <?include ?> node was found, but it specified more than one file.");
502 } 502 }
503 503
504 if(matches.Count == 0) 504 if(matches.Count == 0)
505 { 505 {
506 throw new WarningException("An <?include ?> node was found, but it did not specify the file attribute."); 506 throw new WarningException("An <?include ?> node was found, but it did not specify the file attribute.");
507 } 507 }
508 508
509 // ***** Adding for wildcard handling 509 // ***** Adding for wildcard handling
510 // Push current reader back onto the stack. 510 // Push current reader back onto the stack.
511 readerStack.Push (reader); 511 readerStack.Push (reader);
512 512
513 // Pull the file out from the regex and make sure it is a valid file before using it. 513 // Pull the file out from the regex and make sure it is a valid file before using it.
514 string filename = matches[0].Groups[1].Value; 514 string filename = matches[0].Groups[1].Value;
515 515
516 filename = String.Join (Path.DirectorySeparatorChar.ToString (), filename.Split (new char[] { '/', '\\' })); 516 filename = String.Join (Path.DirectorySeparatorChar.ToString (), filename.Split (new char[] { '/', '\\' }));
517 517
518 if (!filename.Contains ("*")) { 518 if (!filename.Contains ("*")) {
519 519
520 FileInfo includeFile = new FileInfo (filename); 520 FileInfo includeFile = new FileInfo (filename);
521 if (!includeFile.Exists) { 521 if (!includeFile.Exists) {
522 throw new WarningException ("Cannot include file: " + includeFile.FullName); 522 throw new WarningException ("Cannot include file: " + includeFile.FullName);
523 } 523 }
524 524
525 // Create a new reader object for this file. Then put the old reader back on the stack and start 525 // Create a new reader object for this file. Then put the old reader back on the stack and start
526 // processing using this new XML reader. 526 // processing using this new XML reader.
527 527
528 XmlReader newReader = new XmlTextReader (includeFile.Open (FileMode.Open, FileAccess.Read, FileShare.Read)); 528 XmlReader newReader = new XmlTextReader (includeFile.Open (FileMode.Open, FileAccess.Read, FileShare.Read));
529 reader = newReader; 529 reader = newReader;
530 readerStack.Push (reader); 530 readerStack.Push (reader);
531 531
532 } else { 532 } else {
533 WildCardInclude (readerStack, filename); 533 WildCardInclude (readerStack, filename);
534 } 534 }
535 535
536 reader = (XmlReader)readerStack.Pop (); 536 reader = (XmlReader)readerStack.Pop ();
537 ignore = true; 537 ignore = true;
538 break; 538 break;
539 539
540 case "if": 540 case "if":
541 m_IfStack.Push(context); 541 m_IfStack.Push(context);
542 context = new IfContext(context.Keep & context.Active, ParseExpression(reader.Value), IfState.If); 542 context = new IfContext(context.Keep & context.Active, ParseExpression(reader.Value), IfState.If);
543 ignore = true; 543 ignore = true;
544 break; 544 break;
545 545
546 case "elseif": 546 case "elseif":
547 if(m_IfStack.Count == 0) 547 if(m_IfStack.Count == 0)
548 { 548 {
549 throw new WarningException("Unexpected 'elseif' outside of 'if'"); 549 throw new WarningException("Unexpected 'elseif' outside of 'if'");
550 } 550 }
551 if(context.State != IfState.If && context.State != IfState.ElseIf) 551 if(context.State != IfState.If && context.State != IfState.ElseIf)
552 { 552 {
553 throw new WarningException("Unexpected 'elseif' outside of 'if'"); 553 throw new WarningException("Unexpected 'elseif' outside of 'if'");
554 } 554 }
555 555
556 context.State = IfState.ElseIf; 556 context.State = IfState.ElseIf;
557 if(!context.EverKept) 557 if(!context.EverKept)
558 { 558 {
559 context.Keep = ParseExpression(reader.Value); 559 context.Keep = ParseExpression(reader.Value);
560 } 560 }
561 else 561 else
562 { 562 {
563 context.Keep = false; 563 context.Keep = false;
564 } 564 }
565 565
566 ignore = true; 566 ignore = true;
567 break; 567 break;
568 568
569 case "else": 569 case "else":
570 if(m_IfStack.Count == 0) 570 if(m_IfStack.Count == 0)
571 { 571 {
572 throw new WarningException("Unexpected 'else' outside of 'if'"); 572 throw new WarningException("Unexpected 'else' outside of 'if'");
573 } 573 }
574 if(context.State != IfState.If && context.State != IfState.ElseIf) 574 if(context.State != IfState.If && context.State != IfState.ElseIf)
575 { 575 {
576 throw new WarningException("Unexpected 'else' outside of 'if'"); 576 throw new WarningException("Unexpected 'else' outside of 'if'");
577 } 577 }
578 578
579 context.State = IfState.Else; 579 context.State = IfState.Else;
580 context.Keep = !context.EverKept; 580 context.Keep = !context.EverKept;
581 ignore = true; 581 ignore = true;
582 break; 582 break;
583 583
584 case "endif": 584 case "endif":
585 if(m_IfStack.Count == 0) 585 if(m_IfStack.Count == 0)
586 { 586 {
587 throw new WarningException("Unexpected 'endif' outside of 'if'"); 587 throw new WarningException("Unexpected 'endif' outside of 'if'");
588 } 588 }
589 589
590 context = m_IfStack.Pop(); 590 context = m_IfStack.Pop();
591 ignore = true; 591 ignore = true;
592 break; 592 break;
593 } 593 }
594 594
595 if(ignore) 595 if(ignore)
596 { 596 {
597 continue; 597 continue;
598 } 598 }
599 }//end pre-proc instruction 599 }//end pre-proc instruction
600 600
601 if(!context.Active || !context.Keep) 601 if(!context.Active || !context.Keep)
602 { 602 {
603 continue; 603 continue;
604 } 604 }
605 605
606 switch(reader.NodeType) 606 switch(reader.NodeType)
607 { 607 {
608 case XmlNodeType.Element: 608 case XmlNodeType.Element:
609 bool empty = reader.IsEmptyElement; 609 bool empty = reader.IsEmptyElement;
610 writer.WriteStartElement(reader.Name); 610 writer.WriteStartElement(reader.Name);
611 611
612 while (reader.MoveToNextAttribute()) 612 while (reader.MoveToNextAttribute())
613 { 613 {
614 writer.WriteAttributeString(reader.Name, reader.Value); 614 writer.WriteAttributeString(reader.Name, reader.Value);
615 } 615 }
616 616
617 if(empty) 617 if(empty)
618 { 618 {
619 writer.WriteEndElement(); 619 writer.WriteEndElement();
620 } 620 }
621 621
622 break; 622 break;
623 623
624 case XmlNodeType.EndElement: 624 case XmlNodeType.EndElement:
625 writer.WriteEndElement(); 625 writer.WriteEndElement();
626 break; 626 break;
627 627
628 case XmlNodeType.Text: 628 case XmlNodeType.Text:
629 writer.WriteString(reader.Value); 629 writer.WriteString(reader.Value);
630 break; 630 break;
631 631
632 case XmlNodeType.CDATA: 632 case XmlNodeType.CDATA:
633 writer.WriteCData(reader.Value); 633 writer.WriteCData(reader.Value);
634 break; 634 break;
635 635
636 default: 636 default:
637 break; 637 break;
638 } 638 }
639 } 639 }
640 640
641 if(m_IfStack.Count != 0) 641 if(m_IfStack.Count != 0)
642 { 642 {
643 throw new WarningException("Mismatched 'if', 'endif' pair"); 643 throw new WarningException("Mismatched 'if', 'endif' pair");
644 } 644 }
645 } 645 }
646 646
647 return xmlText.ToString(); 647 return xmlText.ToString();
648 } 648 }
649 649
650 #endregion 650 #endregion
651 } 651 }
652} 652}