Configuration file parsing should be complete now (but creation and changing not so much)
git-svn-id: file:///srv/devel/repo-conversion/nusu@303 d2e56fa2-650e-0410-a79f-9358c0239efd
This commit is contained in:
		
							parent
							
								
									7e39bd684f
								
							
						
					
					
						commit
						0753aeb220
					
				
					 3 changed files with 129 additions and 15 deletions
				
			
		| 
						 | 
				
			
			@ -163,15 +163,10 @@ namespace Nuclex.Support.Settings {
 | 
			
		|||
        LineIndex = state.Store.lines.Count - 1,
 | 
			
		||||
        OptionName = new StringSegment(
 | 
			
		||||
          line, firstCharacterIndex, nameEndIndex - firstCharacterIndex + 1
 | 
			
		||||
        ),
 | 
			
		||||
        )
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      // If there is a value in this assignment, parse it too
 | 
			
		||||
      int valueStartIndex = assignmentIndex + 1;
 | 
			
		||||
      ParserHelper.SkipSpaces(line, ref valueStartIndex);
 | 
			
		||||
      if(valueStartIndex < line.Length) {
 | 
			
		||||
        parseOptionValue(option, line, valueStartIndex);
 | 
			
		||||
      }
 | 
			
		||||
      parseOptionValue(option, line, assignmentIndex + 1);
 | 
			
		||||
 | 
			
		||||
      // We've got the option assignment, either with an empty or proper value
 | 
			
		||||
      state.Store.options.Add(option);
 | 
			
		||||
| 
						 | 
				
			
			@ -181,9 +176,54 @@ namespace Nuclex.Support.Settings {
 | 
			
		|||
    /// <summary>Parses the value assigned to an option</summary>
 | 
			
		||||
    /// <param name="option">Option to which a value is being assigned</param>
 | 
			
		||||
    /// <param name="line">Line containing the option assignment</param>
 | 
			
		||||
    /// <param name="valueStartIndex">Index of the value's first character</param>
 | 
			
		||||
    private static void parseOptionValue(Option option, string line, int valueStartIndex) {
 | 
			
		||||
    /// <param name="assignmentEndIndex">Index one after the assignment character</param>
 | 
			
		||||
    private static void parseOptionValue(Option option, string line, int assignmentEndIndex) {
 | 
			
		||||
      int firstCharacterIndex = assignmentEndIndex;
 | 
			
		||||
      ParserHelper.SkipSpaces(line, ref firstCharacterIndex);
 | 
			
		||||
 | 
			
		||||
      // Just for beauty, when the option value is empty but padded with spaces,
 | 
			
		||||
      // leave one space between the equals sign and the value.
 | 
			
		||||
      if(firstCharacterIndex > assignmentEndIndex) {
 | 
			
		||||
        ++assignmentEndIndex;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // If the line consists of only whitespace, create an empty value
 | 
			
		||||
      if(firstCharacterIndex == line.Length) {
 | 
			
		||||
        option.OptionValue = new StringSegment(line, assignmentEndIndex, 0);
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      char firstCharacter = line[firstCharacterIndex];
 | 
			
		||||
 | 
			
		||||
      // Values can be quoted to allow for comments characters appearing in them
 | 
			
		||||
      int lastCharacterIndex;
 | 
			
		||||
      if(firstCharacter == '"') {
 | 
			
		||||
        lastCharacterIndex = line.LastIndexOf('"');
 | 
			
		||||
      } else {
 | 
			
		||||
        lastCharacterIndex = firstCharacterIndex;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      int commentStartIndex = line.IndexOf(';', lastCharacterIndex);
 | 
			
		||||
      if(commentStartIndex == -1) {
 | 
			
		||||
        commentStartIndex = line.IndexOf('#', lastCharacterIndex);
 | 
			
		||||
      }
 | 
			
		||||
      if(commentStartIndex == -1) {
 | 
			
		||||
        lastCharacterIndex = line.Length - 1;
 | 
			
		||||
      } else {
 | 
			
		||||
        lastCharacterIndex = commentStartIndex - 1;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      while(lastCharacterIndex > firstCharacterIndex) {
 | 
			
		||||
        if(char.IsWhiteSpace(line, lastCharacterIndex)) {
 | 
			
		||||
          --lastCharacterIndex;
 | 
			
		||||
        } else {
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      option.OptionValue = new StringSegment(
 | 
			
		||||
        line, firstCharacterIndex, lastCharacterIndex - firstCharacterIndex + 1
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>Determines the best matching type for an option value</summary>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,10 +21,10 @@ License along with this library
 | 
			
		|||
#if UNITTEST
 | 
			
		||||
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.IO;
 | 
			
		||||
 | 
			
		||||
using NUnit.Framework;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace Nuclex.Support.Settings {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -32,6 +32,9 @@ namespace Nuclex.Support.Settings {
 | 
			
		|||
  [TestFixture]
 | 
			
		||||
  internal class ConfigurationFileStoreTest {
 | 
			
		||||
 | 
			
		||||
    /// <summary>Loads a configuration file from a string</summary>
 | 
			
		||||
    /// <param name="fileContents">Contents of the configuration file</param>
 | 
			
		||||
    /// <returns>The configuration file loaded from the string</returns>
 | 
			
		||||
    private static ConfigurationFileStore load(string fileContents) {
 | 
			
		||||
      using(var reader = new StringReader(fileContents)) {
 | 
			
		||||
        return ConfigurationFileStore.Parse(reader);
 | 
			
		||||
| 
						 | 
				
			
			@ -128,11 +131,84 @@ namespace Nuclex.Support.Settings {
 | 
			
		|||
 | 
			
		||||
      for(int index = 0; index < options.Count; ++index) {
 | 
			
		||||
        Assert.That(
 | 
			
		||||
          configurationFile.Get<string>(null, options[index].Name), Is.Null
 | 
			
		||||
          configurationFile.Get<string>(null, options[index].Name), Is.Null.Or.Empty
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    ///   Verifies that values assigned to options can contain space charcters
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    [Test]
 | 
			
		||||
    public void OptionValuesCanContainSpaces() {
 | 
			
		||||
      string fileContents =
 | 
			
		||||
        "test = hello world";
 | 
			
		||||
      ConfigurationFileStore configurationFile = load(fileContents);
 | 
			
		||||
 | 
			
		||||
      Assert.That(configurationFile.Get<string>(null, "test"), Is.EqualTo("hello world"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    ///   Verifies that values enclosed in quotes can embed comment characters
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    [Test]
 | 
			
		||||
    public void OptionValuesWithQuotesCanEmbedComments() {
 | 
			
		||||
      string fileContents =
 | 
			
		||||
        "test = \"This ; is # not a comment\" # but this is";
 | 
			
		||||
      ConfigurationFileStore configurationFile = load(fileContents);
 | 
			
		||||
 | 
			
		||||
      Assert.That(
 | 
			
		||||
        configurationFile.Get<string>(null, "test"),
 | 
			
		||||
        Is.EqualTo("\"This ; is # not a comment\"")
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    ///   Verifies that values can end on a quote without causing trouble
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    [Test]
 | 
			
		||||
    public void CommentsCanEndWithAQuote() {
 | 
			
		||||
      string fileContents =
 | 
			
		||||
        "test = \"This value ends with a quote\"";
 | 
			
		||||
      ConfigurationFileStore configurationFile = load(fileContents);
 | 
			
		||||
 | 
			
		||||
      Assert.That(
 | 
			
		||||
        configurationFile.Get<string>(null, "test"),
 | 
			
		||||
        Is.EqualTo("\"This value ends with a quote\"")
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    ///   Verifies that values can forget the closing quote without causing trouble
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    [Test]
 | 
			
		||||
    public void ClosingQuoteCanBeOmmitted() {
 | 
			
		||||
      string fileContents =
 | 
			
		||||
        "test = \"No closing quote";
 | 
			
		||||
      ConfigurationFileStore configurationFile = load(fileContents);
 | 
			
		||||
 | 
			
		||||
      Assert.That(
 | 
			
		||||
        configurationFile.Get<string>(null, "test"),
 | 
			
		||||
        Is.EqualTo("\"No closing quote")
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    ///   Verifies that text placed after the closing quote will also be part of
 | 
			
		||||
    ///   an option's value
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    [Test]
 | 
			
		||||
    public void TextAfterClosingQuoteBecomesPartOfValue() {
 | 
			
		||||
      string fileContents =
 | 
			
		||||
        "test = \"Begins here\" end ends here";
 | 
			
		||||
      ConfigurationFileStore configurationFile = load(fileContents);
 | 
			
		||||
 | 
			
		||||
      Assert.That(
 | 
			
		||||
        configurationFile.Get<string>(null, "test"),
 | 
			
		||||
        Is.EqualTo("\"Begins here\" end ends here")
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
} // namespace Nuclex.Support.Settings
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,8 +21,6 @@ License along with this library
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.IO;
 | 
			
		||||
 | 
			
		||||
using Nuclex.Support.Parsing;
 | 
			
		||||
using System.Text;
 | 
			
		||||
 | 
			
		||||
namespace Nuclex.Support.Settings {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue