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.cs272
1 files changed, 107 insertions, 165 deletions
diff --git a/Prebuild/src/Core/Parse/Preprocessor.cs b/Prebuild/src/Core/Parse/Preprocessor.cs
index 013f8e1..eea5c30 100644
--- a/Prebuild/src/Core/Parse/Preprocessor.cs
+++ b/Prebuild/src/Core/Parse/Preprocessor.cs
@@ -23,10 +23,18 @@ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY O
23*/ 23*/
24#endregion 24#endregion
25 25
26#region CVS Information
27/*
28 * $Source$
29 * $Author: jendave $
30 * $Date: 2007-04-26 17:10:27 +0900 (Thu, 26 Apr 2007) $
31 * $Revision: 236 $
32 */
33#endregion
34
26using System; 35using System;
27using System.Collections; 36using System.Collections;
28using System.IO; 37using System.IO;
29using System.Text.RegularExpressions;
30using System.Xml; 38using System.Xml;
31 39
32namespace Prebuild.Core.Parse 40namespace Prebuild.Core.Parse
@@ -71,16 +79,6 @@ namespace Prebuild.Core.Parse
71 /// </summary> 79 /// </summary>
72 public class Preprocessor 80 public class Preprocessor
73 { 81 {
74 #region Constants
75
76 /// <summary>
77 /// Includes the regex to look for file tags in the <?include
78 /// ?> processing instruction.
79 /// </summary>
80 private static readonly Regex includeFileRegex = new Regex("file=\"(.+?)\"");
81
82 #endregion
83
84 #region Fields 82 #region Fields
85 83
86 XmlDocument m_OutDoc; 84 XmlDocument m_OutDoc;
@@ -140,10 +138,10 @@ namespace Prebuild.Core.Parse
140 return "Win32"; 138 return "Win32";
141 } 139 }
142 140
143 if (File.Exists("/System/Library/Frameworks/Cocoa.framework/Cocoa")) 141 if (File.Exists("/System/Library/Frameworks/Cocoa.framework/Cocoa"))
144 { 142 {
145 return "MACOSX"; 143 return "MACOSX";
146 } 144 }
147 145
148 /* 146 /*
149 * .NET 1.x, under Mono, the UNIX code is 128. Under 147 * .NET 1.x, under Mono, the UNIX code is 128. Under
@@ -238,7 +236,7 @@ namespace Prebuild.Core.Parse
238 OperatorSymbol oper = OperatorSymbol.None; 236 OperatorSymbol oper = OperatorSymbol.None;
239 bool inStr = false; 237 bool inStr = false;
240 char c; 238 char c;
241 239
242 for(int i = 0; i < exp.Length; i++) 240 for(int i = 0; i < exp.Length; i++)
243 { 241 {
244 c = exp[i]; 242 c = exp[i];
@@ -285,7 +283,7 @@ namespace Prebuild.Core.Parse
285 { 283 {
286 oper = OperatorSymbol.NotEqual; 284 oper = OperatorSymbol.NotEqual;
287 } 285 }
288 286
289 break; 287 break;
290 288
291 case '<': 289 case '<':
@@ -297,7 +295,7 @@ namespace Prebuild.Core.Parse
297 { 295 {
298 oper = OperatorSymbol.LessThan; 296 oper = OperatorSymbol.LessThan;
299 } 297 }
300 298
301 break; 299 break;
302 300
303 case '>': 301 case '>':
@@ -316,7 +314,7 @@ namespace Prebuild.Core.Parse
316 } 314 }
317 } 315 }
318 316
319 317
320 if(inStr) 318 if(inStr)
321 { 319 {
322 throw new WarningException("Expected end of string in expression"); 320 throw new WarningException("Expected end of string in expression");
@@ -394,9 +392,9 @@ namespace Prebuild.Core.Parse
394 /// <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> 392 /// <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>
395 /// <param name="reader"></param> 393 /// <param name="reader"></param>
396 /// <returns>the output xml </returns> 394 /// <returns>the output xml </returns>
397 public string Process(XmlReader initialReader) 395 public string Process(XmlReader reader)
398 { 396 {
399 if(initialReader == null) 397 if(reader == null)
400 { 398 {
401 throw new ArgumentException("Invalid XML reader to pre-process"); 399 throw new ArgumentException("Invalid XML reader to pre-process");
402 } 400 }
@@ -405,175 +403,119 @@ namespace Prebuild.Core.Parse
405 StringWriter xmlText = new StringWriter(); 403 StringWriter xmlText = new StringWriter();
406 XmlTextWriter writer = new XmlTextWriter(xmlText); 404 XmlTextWriter writer = new XmlTextWriter(xmlText);
407 writer.Formatting = Formatting.Indented; 405 writer.Formatting = Formatting.Indented;
408 406 while(reader.Read())
409 // Create a queue of XML readers and add the initial
410 // reader to it. Then we process until we run out of
411 // readers which lets the <?include?> operation add more
412 // readers to generate a multi-file parser and not require
413 // XML fragments that a recursive version would use.
414 Stack readerStack = new Stack();
415 readerStack.Push(initialReader);
416
417 while(readerStack.Count > 0)
418 { 407 {
419 // Pop off the next reader. 408 if(reader.NodeType == XmlNodeType.ProcessingInstruction)
420 XmlReader reader = (XmlReader) readerStack.Pop();
421
422 // Process through this XML reader until it is
423 // completed (or it is replaced by the include
424 // operation).
425 while(reader.Read())
426 { 409 {
427 // The prebuild file has a series of processing 410 bool ignore = false;
428 // instructions which allow for specific 411 switch(reader.LocalName)
429 // inclusions based on operating system or to
430 // include additional files.
431 if(reader.NodeType == XmlNodeType.ProcessingInstruction)
432 { 412 {
433 bool ignore = false; 413 case "if":
434 414 m_IfStack.Push(context);
435 switch(reader.LocalName) 415 context = new IfContext(context.Keep & context.Active, ParseExpression(reader.Value), IfState.If);
436 { 416 ignore = true;
437 case "include": 417 break;
438 // use regular expressions to parse out the attributes.
439 MatchCollection matches = includeFileRegex.Matches(reader.Value);
440
441 // make sure there is only one file attribute.
442 if(matches.Count > 1)
443 {
444 throw new WarningException("An <?include ?> node was found, but it specified more than one file.");
445 }
446
447 if(matches.Count == 0)
448 {
449 throw new WarningException("An <?include ?> node was found, but it did not specify the file attribute.");
450 }
451
452 // Pull the file out from the regex and make sure it is a valid file before using it.
453 string filename = matches[0].Groups[1].Value;
454 FileInfo includeFile = new FileInfo(filename);
455
456 if(!includeFile.Exists)
457 {
458 throw new WarningException("Cannot include file: " + includeFile.FullName);
459 }
460
461 // Create a new reader object for this file. Then put the old reader back on the stack and start
462 // processing using this new XML reader.
463 XmlReader newReader = new XmlTextReader(includeFile.Open(FileMode.Open, FileAccess.Read, FileShare.Read));
464
465 readerStack.Push(reader);
466 reader = newReader;
467 ignore = true;
468 break;
469
470 case "if":
471 m_IfStack.Push(context);
472 context = new IfContext(context.Keep & context.Active, ParseExpression(reader.Value), IfState.If);
473 ignore = true;
474 break;
475
476 case "elseif":
477 if(m_IfStack.Count == 0)
478 {
479 throw new WarningException("Unexpected 'elseif' outside of 'if'");
480 }
481 else if(context.State != IfState.If && context.State != IfState.ElseIf)
482 {
483 throw new WarningException("Unexpected 'elseif' outside of 'if'");
484 }
485 418
486 context.State = IfState.ElseIf; 419 case "elseif":
487 if(!context.EverKept) 420 if(m_IfStack.Count == 0)
488 { 421 {
489 context.Keep = ParseExpression(reader.Value); 422 throw new WarningException("Unexpected 'elseif' outside of 'if'");
490 } 423 }
491 else 424 else if(context.State != IfState.If && context.State != IfState.ElseIf)
492 { 425 {
493 context.Keep = false; 426 throw new WarningException("Unexpected 'elseif' outside of 'if'");
494 } 427 }
495 428
496 ignore = true; 429 context.State = IfState.ElseIf;
497 break; 430 if(!context.EverKept)
431 {
432 context.Keep = ParseExpression(reader.Value);
433 }
434 else
435 {
436 context.Keep = false;
437 }
498 438
499 case "else": 439 ignore = true;
500 if(m_IfStack.Count == 0) 440 break;
501 {
502 throw new WarningException("Unexpected 'else' outside of 'if'");
503 }
504 else if(context.State != IfState.If && context.State != IfState.ElseIf)
505 {
506 throw new WarningException("Unexpected 'else' outside of 'if'");
507 }
508 441
509 context.State = IfState.Else; 442 case "else":
510 context.Keep = !context.EverKept; 443 if(m_IfStack.Count == 0)
511 ignore = true; 444 {
512 break; 445 throw new WarningException("Unexpected 'else' outside of 'if'");
446 }
447 else if(context.State != IfState.If && context.State != IfState.ElseIf)
448 {
449 throw new WarningException("Unexpected 'else' outside of 'if'");
450 }
513 451
514 case "endif": 452 context.State = IfState.Else;
515 if(m_IfStack.Count == 0) 453 context.Keep = !context.EverKept;
516 { 454 ignore = true;
517 throw new WarningException("Unexpected 'endif' outside of 'if'"); 455 break;
518 }
519 456
520 context = (IfContext)m_IfStack.Pop(); 457 case "endif":
521 ignore = true; 458 if(m_IfStack.Count == 0)
522 break; 459 {
523 } 460 throw new WarningException("Unexpected 'endif' outside of 'if'");
461 }
524 462
525 if(ignore) 463 context = (IfContext)m_IfStack.Pop();
526 { 464 ignore = true;
527 continue; 465 break;
528 } 466 }
529 }//end pre-proc instruction
530 467
531 if(!context.Active || !context.Keep) 468 if(ignore)
532 { 469 {
533 continue; 470 continue;
534 } 471 }
472 }//end pre-proc instruction
535 473
536 switch(reader.NodeType) 474 if(!context.Active || !context.Keep)
537 { 475 {
538 case XmlNodeType.Element: 476 continue;
539 bool empty = reader.IsEmptyElement; 477 }
540 writer.WriteStartElement(reader.Name);
541 478
542 while (reader.MoveToNextAttribute()) 479 switch(reader.NodeType)
543 { 480 {
544 writer.WriteAttributeString(reader.Name, reader.Value); 481 case XmlNodeType.Element:
545 } 482 bool empty = reader.IsEmptyElement;
483 writer.WriteStartElement(reader.Name);
546 484
547 if(empty) 485 while (reader.MoveToNextAttribute())
548 { 486 {
549 writer.WriteEndElement(); 487 writer.WriteAttributeString(reader.Name, reader.Value);
550 } 488 }
551
552 break;
553 489
554 case XmlNodeType.EndElement: 490 if(empty)
491 {
555 writer.WriteEndElement(); 492 writer.WriteEndElement();
556 break; 493 }
494
495 break;
557 496
558 case XmlNodeType.Text: 497 case XmlNodeType.EndElement:
559 writer.WriteString(reader.Value); 498 writer.WriteEndElement();
560 break; 499 break;
561 500
562 case XmlNodeType.CDATA: 501 case XmlNodeType.Text:
563 writer.WriteCData(reader.Value); 502 writer.WriteString(reader.Value);
564 break; 503 break;
565 504
566 default: 505 case XmlNodeType.CDATA:
567 break; 506 writer.WriteCData(reader.Value);
568 } 507 break;
569 }
570 508
571 if(m_IfStack.Count != 0) 509 default:
572 { 510 break;
573 throw new WarningException("Mismatched 'if', 'endif' pair");
574 } 511 }
575 } 512 }
576 513
514 if(m_IfStack.Count != 0)
515 {
516 throw new WarningException("Mismatched 'if', 'endif' pair");
517 }
518
577 return xmlText.ToString(); 519 return xmlText.ToString();
578 } 520 }
579 521