Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extended sections #6

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 137 additions & 15 deletions Source/Ini/IniDocument.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public class IniDocument
IniSectionCollection sections = new IniSectionCollection ();
ArrayList initialComment = new ArrayList ();
IniFileType fileType = IniFileType.Standard;
bool extended = false;
#endregion

#region Public properties
Expand All @@ -52,52 +53,108 @@ public IniFileType FileType

#region Constructors
/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorPath"]/docs/*' />
public IniDocument (string filePath)
public IniDocument(string filePath)
{
fileType = IniFileType.Standard;
Load (filePath);
Load(filePath);
}

/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorPath"]/docs/*' />
public IniDocument(string filePath, bool supportExtended)
{
fileType = IniFileType.Standard;
extended = supportExtended;
Load(filePath);
}

/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorPathType"]/docs/*' />
public IniDocument(string filePath, IniFileType type)
{
fileType = type;
Load(filePath);
}

/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorPathType"]/docs/*' />
public IniDocument (string filePath, IniFileType type)
public IniDocument(string filePath, IniFileType type, bool supportExtended)
{
fileType = type;
Load (filePath);
extended = supportExtended;
Load(filePath);
}

/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorTextReader"]/docs/*' />
public IniDocument (TextReader reader)
public IniDocument(TextReader reader)
{
fileType = IniFileType.Standard;
Load (reader);
Load(reader);
}

/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorTextReader"]/docs/*' />
public IniDocument(TextReader reader, bool supportExtended)
{
fileType = IniFileType.Standard;
extended = supportExtended;
Load(reader);
}

/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorTextReaderType"]/docs/*' />
public IniDocument (TextReader reader, IniFileType type)
public IniDocument(TextReader reader, IniFileType type)
{
fileType = type;
Load (reader);
Load(reader);
}


/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorTextReaderType"]/docs/*' />
public IniDocument(TextReader reader, IniFileType type, bool supportExtended)
{
fileType = type;
extended = supportExtended;
Load(reader);
}

/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorStream"]/docs/*' />
public IniDocument (Stream stream)
public IniDocument(Stream stream)
{
fileType = IniFileType.Standard;
Load (stream);
Load(stream);
}

/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorStream"]/docs/*' />
public IniDocument(Stream stream, bool supportExtended)
{
fileType = IniFileType.Standard;
extended = supportExtended;
Load(stream);
}

/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorStreamType"]/docs/*' />
public IniDocument(Stream stream, IniFileType type)
{
fileType = type;
Load(stream);
}

/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorStreamType"]/docs/*' />
public IniDocument (Stream stream, IniFileType type)
public IniDocument(Stream stream, IniFileType type, bool supportExtended)
{
fileType = type;
Load (stream);
extended = supportExtended;
Load(stream);
}

/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorIniReader"]/docs/*' />
public IniDocument(IniReader reader)
{
fileType = IniFileType.Standard;
Load(reader);
}

/// <include file='IniDocument.xml' path='//Constructor[@name="ConstructorIniReader"]/docs/*' />
public IniDocument (IniReader reader)
public IniDocument(IniReader reader, bool supportExtended)
{
fileType = IniFileType.Standard;
Load (reader);
extended = supportExtended;
Load(reader);
}

/// <include file='IniDocument.xml' path='//Constructor[@name="Constructor"]/docs/*' />
Expand Down Expand Up @@ -232,6 +289,71 @@ private void LoadReader (IniReader reader)
// Always close the file
reader.Close ();
}

MergeSections();
}

/// <summary>
/// Supports section merging where a colon is in the key, e.g. ExtendedSection : BaseSection
/// </summary>
private void MergeSections()
{
if(!extended)
{
return;
}

foreach (DictionaryEntry entry in sections)
{
IniSection section = (IniSection)entry.Value;

if (!section.Name.Contains(":"))
{
continue;
}

var parts = section.Name.Split(new char[] { ':' });
var newName = parts[0].TrimEnd();
var extendedSectionName = parts[1].TrimStart();

if (sections[newName] != null)
{
sections.Remove(newName);
}

if (sections[extendedSectionName] == null)
{
throw new ArgumentException(String.Format("Section {0} is trying to extend section {1} but it does not exist.", newName, extendedSectionName));
}

IniSection baseSection = sections[extendedSectionName];
var baseKeys = baseSection.GetKeys();

var newSection = new IniSection(newName, section.Comment);

for (var i = 0; i < baseSection.ItemCount; i++)
{
var item = baseSection.GetItem(i);

if (item.Value != null)
{
newSection.Set(item.Name, item.Value, item.Comment);
}
}

for (var i = 0; i < section.ItemCount; i++)
{
var item = section.GetItem(i);

if (item.Value != null)
{
newSection.Set(item.Name, item.Value, item.Comment);
}
}

sections.Add(newSection);
sections.Remove(section.Name);
}
}

/// <summary>
Expand Down
7 changes: 5 additions & 2 deletions Source/Test/Config/ConfigBaseTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,11 @@ public void GetFloat ()
IniConfigSource source = new IniConfigSource
(new StringReader (writer.ToString ()));
IConfig config = source.Configs["Test"];

Assert.AreEqual (494.59, config.GetFloat ("value 1"));

// Compensate for floating point storage.
var comparison = Math.Abs(494.59 - config.GetFloat("value 1"));
Assert.Less(comparison, 0.0001);

Assert.AreEqual ((float)5656.2853,
config.GetFloat ("Not Here", (float)5656.2853));
}
Expand Down
35 changes: 35 additions & 0 deletions Source/Test/Ini/IniDocumentTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,41 @@ public void DuplicateSections ()
Assert.IsNotNull (doc.Sections["Test"].GetValue ("value 1"));
}

[Test]
public void ExtendedSections ()
{
StringWriter writer = new StringWriter();
writer.WriteLine("[ExtendedSection : BaseSection]");
writer.WriteLine("keyB = overwrittenB");
writer.WriteLine("keyC = valueC");
writer.WriteLine("[BaseSection]");
writer.WriteLine("keyA = valueA");
writer.WriteLine("keyB = valueB");

IniDocument doc = new IniDocument(new StringReader(writer.ToString()), true);

Assert.IsNotNull(doc.Sections["BaseSection"], "BaseSection is null");
Assert.IsNotNull(doc.Sections["ExtendedSection"], "ExtendedSection is null");
Assert.IsNull(doc.Sections["ExtendedSection : BaseSection"], "ExtendedSection:BaseSection is not null");
Assert.AreEqual(2, doc.Sections.Count);

Assert.AreEqual("valueA", doc.Sections["BaseSection"].GetValue("keyA"));
Assert.AreEqual("valueB", doc.Sections["BaseSection"].GetValue("keyB"));

Assert.AreEqual("valueC", doc.Sections["ExtendedSection"].GetValue("keyC"));
Assert.AreEqual("overwrittenB", doc.Sections["ExtendedSection"].GetValue("keyB"));
}

[Test]
[ExpectedException(ExpectedException = typeof(ArgumentException), ExpectedMessage = "Section ExtendedSection is trying to extend section BaseSectionInvalid but it does not exist", MatchType = MessageMatch.Contains)]
public void ExtendedSectionsValidNames()
{
StringWriter writer = new StringWriter();
writer.WriteLine("[ExtendedSection : BaseSectionInvalid]");

IniDocument doc = new IniDocument(new StringReader(writer.ToString()), true);
}

[Test]
public void DuplicateKeys ()
{
Expand Down