Skip to content

Commit

Permalink
Merge branch 'development'
Browse files Browse the repository at this point in the history
* development:
  Ignore Visual Studio Code files
  Fixed issue 88, added support for quotes
  Added possibility to pass IniDataParser to ctor of FileIniDataParser
  Move separator character to IniData
  Tweaked commenting
  Add link to nuget package
  Added TryGetKey/GetKey to IniData
  • Loading branch information
rickyah committed Dec 9, 2015
2 parents d40db0c + f25f943 commit 85c7f9b
Show file tree
Hide file tree
Showing 7 changed files with 214 additions and 3 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pack
*.nupkg
lib
*.symbols.nuspec
.vscode

# Visual Studio ignores

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Also implements merging operations, both for complete ini files, sections, or ev


Get the latest version: https://github.com/rickyah/ini-parser/releases/latest
Install it with NuGet: https://www.nuget.org/packages/ini-parser/

## Version 2.0
Since the INI format isn't really a "standard", version 2 introduces a simpler way to customize INI parsing:
Expand Down
94 changes: 94 additions & 0 deletions src/IniFileParser.Tests/Unit/Model/INIDataTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,100 @@ public void check_add_keydata_method_using_key_and_value_strings()

Assert.That(newData["newSection"]["newKey1"], Is.EqualTo("value1"));
}

[Test, Description("Tests preconditions for TryGetKey")]
public void TryGetKey_preconditions()
{
var data = new IniDataParser().Parse("");
var separator = data.SectionKeySeparator;
string result;

// ensure that various good keys aren't rejected
var goodKey = "";
Assert.DoesNotThrow(() => data.TryGetKey(goodKey, out result));
goodKey = "key";
Assert.DoesNotThrow(() => data.TryGetKey(goodKey, out result));
goodKey = string.Format("section{0}key", separator);
Assert.DoesNotThrow(() => data.TryGetKey(goodKey, out result));

// should be rejected
var badKey = string.Format("section{0}subsection{0}key", separator);
Assert.Throws<ArgumentException>(() => data.TryGetKey(badKey, out result));
}

[Test, Description("Tests retrieving data with TryGetKey")]
public void TryGetKey_data_retrieval()
{
var input = @"
global = 1
[section1]
key1 = 2
[section1\subsection]
key2 = 3
";
var data = new IniDataParser().Parse(input);
var separator = data.SectionKeySeparator;
string key;
string result;

// keys should all be retrieved
Assert.IsTrue(data.TryGetKey("global", out result));
Assert.AreEqual(result, "1");

key = string.Format("section1{0}key1", separator);
Assert.IsTrue(data.TryGetKey(key, out result));
Assert.AreEqual(result, "2");

key = string.Format(@"section1\subsection{0}key2", separator);
Assert.IsTrue(data.TryGetKey(key, out result));
Assert.AreEqual(result, "3");

// invalid keys should fail...
Assert.IsFalse(data.TryGetKey(null, out result));
Assert.That(result, Is.Empty);

Assert.IsFalse(data.TryGetKey("", out result));
Assert.That(result, Is.Empty);

Assert.IsFalse(data.TryGetKey("badglobal", out result));
Assert.That(result, Is.Empty);

key = string.Format("badsection{0}badkey", separator);
Assert.IsFalse(data.TryGetKey(key, out result));
Assert.That(result, Is.Empty);
}

// GetKey shares preconditions with TryGetKey, so tests are not duplicated
[Test, Description("Tests retrieving data with GetKey")]
public void GeyKey_data_retrieval()
{
var input = @"
global = 1
[section]
key = 2
";
var data = new IniDataParser().Parse(input);
var separator = data.SectionKeySeparator;
string key;

// should succeed
key = "global";
Assert.AreEqual(data.GetKey(key), "1");

key = string.Format("section{0}key", separator);
Assert.AreEqual(data.GetKey(key), "2");

// should fail
key = null;
Assert.IsNull(data.GetKey(key));

key = "badglobal";
Assert.IsNull(data.GetKey(key));

key = string.Format("badsection{0}badkey", separator);
Assert.IsNull(data.GetKey(key));
}
}
}

15 changes: 14 additions & 1 deletion src/IniFileParser.Tests/Unit/Parser/ParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,19 @@ public void provides_a_list_of_errors()

}


[Test, Description("Test for Issue 88: https://github.com/rickyah/ini-parser/issues/88")]
public void allow_quotes_in_sections()
{
var parser = new IniDataParser();

var iniDataString = @"[W101 0.5"" wc]
key = value
[W103 0.5' wc]
key2 = value2";
IniData parsedData = parser.Parse(iniDataString);

Assert.That(parsedData.Sections["W101 0.5\" wc"], Is.Not.Empty);
Assert.That(parsedData.Sections["W103 0.5' wc"], Is.Not.Empty);
}
}
}
15 changes: 15 additions & 0 deletions src/IniFileParser/FileIniParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Text;
using IniParser.Exceptions;
using IniParser.Model;
using IniParser.Parser;

namespace IniParser
{
Expand All @@ -11,6 +12,20 @@ namespace IniParser
/// </summary>
public class FileIniDataParser : StreamIniDataParser
{
/// <summary>
/// Ctor
/// </summary>
public FileIniDataParser() {}

/// <summary>
/// Ctor
/// </summary>
/// <param name="parser"></param>
public FileIniDataParser(IniDataParser parser) : base(parser)
{
Parser = parser;
}

#region Deprecated methods

[Obsolete("Please use ReadFile method instead of this one as is more semantically accurate")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public IniParserConfiguration(IniParserConfiguration ori)
CommentString = ori.CommentString;
ThrowExceptionsOnError = ori.ThrowExceptionsOnError;

// Regex values should recreate themselves.
// Regex values should recreate themselves.
}
#endregion

Expand Down Expand Up @@ -262,7 +262,7 @@ public string CommentString
#region Constants
protected const string _strCommentRegex = @"^{0}(.*)";
protected const string _strSectionRegexStart = @"^(\s*?)";
protected const string _strSectionRegexMiddle = @"{1}\s*[_\{\}\#\+\;\*\%\(\)\=\?\&\$\,\:\/\.\-\w\d\s\\\~]+\s*";
protected const string _strSectionRegexMiddle = @"{1}\s*[_\""\'\{\}\#\+\;\*\%\(\)\=\?\&\$\,\:\/\.\-\w\d\s\\\~]+\s*";
protected const string _strSectionRegexEnd = @"(\s*?)$";
protected const string _strKeyRegex = @"^(\s*[_\.\d\w]*\s*)";
protected const string _strValueRegex = @"([\s\d\w\W\.]*)$";
Expand Down
87 changes: 87 additions & 0 deletions src/IniFileParser/Model/IniData.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Net;
using IniParser.Model.Configuration;
using IniParser.Model.Formatting;

Expand Down Expand Up @@ -37,6 +38,7 @@ public IniData(SectionDataCollection sdc)
{
_sections = (SectionDataCollection)sdc.Clone();
Global = new KeyDataCollection();
SectionKeySeparator = '.';
}

public IniData(IniData ori): this((SectionDataCollection) ori.Sections)
Expand Down Expand Up @@ -103,6 +105,15 @@ public SectionDataCollection Sections
get { return _sections; }
set { _sections = value; }
}

/// <summary>
/// Used to mark the separation between the section name and the key name
/// when using <see cref="IniData.TryGetKey"/>.
/// </summary>
/// <remarks>
/// Defaults to '.'.
/// </remarks>
public char SectionKeySeparator { get; set; }
#endregion

#region Object Methods
Expand Down Expand Up @@ -171,6 +182,82 @@ public void Merge(IniData toMergeIniData)

}

/// <summary>
/// Attempts to retrieve a key, using a single string combining section and
/// key name.
/// </summary>
/// <param name="key">
/// The section and key name to retrieve, separated by <see cref="IniParserConfiguration.SectionKeySeparator"/>.
///
/// If key contains no separator, it is treated as a key in the <see cref="Global"/> section.
///
/// Key may contain no more than one separator character.
/// </param>
/// <param name="value">
/// If true is returned, is set to the value retrieved. Otherwise, is set
/// to an empty string.
/// </param>
/// <returns>
/// True if key was found, otherwise false.
/// </returns>
/// <exception cref="ArgumentException">
/// key contained multiple separators.
/// </exception>
public bool TryGetKey(string key, out string value)
{
value = string.Empty;
if (string.IsNullOrEmpty(key))
return false;

var splitKey = key.Split(SectionKeySeparator);
var separatorCount = splitKey.Length - 1;
if (separatorCount > 1)
throw new ArgumentException("key contains multiple separators", "key");

if (separatorCount == 0)
{
if (!Global.ContainsKey(key))
return false;

value = Global[key];
return true;
}

var section = splitKey[0];
key = splitKey[1];

if (!_sections.ContainsSection(section))
return false;
var sectionData = _sections[section];
if (!sectionData.ContainsKey(key))
return false;

value = sectionData[key];
return true;
}

/// <summary>
/// Retrieves a key using a single input string combining section and key name.
/// </summary>
/// <param name="key">
/// The section and key name to retrieve, separated by <see cref="IniParserConfiguration.SectionKeySeparator"/>.
///
/// If key contains no separator, it is treated as a key in the <see cref="Global"/> section.
///
/// Key may contain no more than one separator character.
/// </param>
/// <returns>
/// The key's value if it was found, otherwise null.
/// </returns>
/// <exception cref="ArgumentException">
/// key contained multiple separators.
/// </exception>
public string GetKey(string key)
{
string result;
return TryGetKey(key, out result) ? result : null;
}

/// <summary>
/// Merge the sections into this by overwriting this sections.
/// </summary>
Expand Down

0 comments on commit 85c7f9b

Please sign in to comment.