diff --git a/Nuclex.Support (net-4.0).csproj b/Nuclex.Support (net-4.0).csproj index 14255fb..efa4c66 100644 --- a/Nuclex.Support (net-4.0).csproj +++ b/Nuclex.Support (net-4.0).csproj @@ -197,6 +197,14 @@ WeakCollection.cs + + + ConfigurationFileStore.cs + + + + + diff --git a/Source/Configuration/ConfigurationFile.cs b/Source/Configuration/ConfigurationFile.cs deleted file mode 100644 index f953541..0000000 --- a/Source/Configuration/ConfigurationFile.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; - -namespace Nuclex.Support.Configuration { - - /// Represents an ini- or cfg-like configuration file - /// - /// This class tries its best to preserve the formatting of configuration files. - /// Changing a value will keep the line it appears in intact. - /// - public class ConfigurationFile { - - /// Initializes a new, empty configuration file - public ConfigurationFile() { - this.lines = new List(); - } - - /// Parses a configuration file from the specified text reader - /// Reader the configuration file will be parsed from - /// The configuration file parsed from the specified reader - public static ConfigurationFile Parse(TextReader reader) { - throw new NotImplementedException(); - } - - /// Saves the configuration file into the specified writer - /// Writer the configuration file will be saved into - public void Save(TextWriter writer) { - - } - - /// Lines contained in the configuration file - private IList lines; - - } - -} // namespace Nuclex.Support.Configuration diff --git a/Source/Configuration/ConfigurationFileStore.Parsing.cs b/Source/Configuration/ConfigurationFileStore.Parsing.cs new file mode 100644 index 0000000..aa633d1 --- /dev/null +++ b/Source/Configuration/ConfigurationFileStore.Parsing.cs @@ -0,0 +1,139 @@ +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2014 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +using System; +using System.IO; + +using Nuclex.Support.Parsing; + +namespace Nuclex.Support.Configuration { + + partial class ConfigurationFileStore { + + /// Parses a configuration file from the specified text reader + /// Reader the configuration file will be parsed from + /// The configuration file parsed from the specified reader + public static ConfigurationFileStore Parse(TextReader reader) { + var store = new ConfigurationFileStore(); + + for(; ; ) { + string line = reader.ReadLine(); + if(line == null) { + return store; + } + + + } + } + + /// Determines the best matching type for an option value + /// Value for which the best matching type will be found + /// The best matching type for the specified option value + private static Type getBestMatchingType(ref StringSegment value) { + if(value.Count == 0) { + return typeof(string); + } + + // If there are at least two characters, it may be an integer with + // a sign in front of it + if(value.Count >= 2) { + int index = value.Offset; + if(ParserHelper.SkipInteger(value.Text, ref index)) { + if(index < value.Offset + value.Count) { + if(value.Text[index] == '.') { + return typeof(float); + } + } + + return typeof(int); + } + } else if(value.Count >= 1) { // If it's at least one character, it may be a number + int index = value.Offset; + ParserHelper.SkipNumericals(value.Text, ref index); + if(index > value.Offset) { + return typeof(int); + } + } + + // If it parses as a boolean literal, then it must be a boolean + if(parseBooleanLiteral(ref value) != null) { + return typeof(bool); + } + + return typeof(string); + } + + /// Tried to parse a boolean literal + /// Value that will be parsed as a boolean literal + /// + /// True or false if the value was a boolean literal, null if it wasn't + /// + private static bool? parseBooleanLiteral(ref StringSegment value) { + switch(value.Count) { + + // If the string spells 'no', it is considered a boolean + case 2: { + bool isSpellingNo = + ((value.Text[value.Offset + 0] == 'n') || (value.Text[value.Offset + 0] == 'N')) && + ((value.Text[value.Offset + 1] == 'o') || (value.Text[value.Offset + 1] == 'O')); + return isSpellingNo ? new Nullable(false) : null; + } + + // If the string spells 'yes', it is considered a boolean + case 3: { + bool isSpellingYes = + ((value.Text[value.Offset + 0] == 'y') || (value.Text[value.Offset + 0] == 'Y')) && + ((value.Text[value.Offset + 1] == 'e') || (value.Text[value.Offset + 1] == 'E')) && + ((value.Text[value.Offset + 2] == 's') || (value.Text[value.Offset + 2] == 'S')); + return isSpellingYes ? new Nullable(true) : null; + } + + // If the string spells 'true', it is considered a boolean + case 4: { + bool isSpellingTrue = + ((value.Text[value.Offset + 0] == 't') || (value.Text[value.Offset + 0] == 'T')) && + ((value.Text[value.Offset + 1] == 'r') || (value.Text[value.Offset + 1] == 'R')) && + ((value.Text[value.Offset + 2] == 'u') || (value.Text[value.Offset + 2] == 'U')) && + ((value.Text[value.Offset + 3] == 'e') || (value.Text[value.Offset + 3] == 'E')); + return isSpellingTrue ? new Nullable(true) : null; + } + + // If the string spells 'false', it is considered a boolean + case 5: { + bool isSpellingFalse = + ((value.Text[value.Offset + 0] == 'f') || (value.Text[value.Offset + 0] == 'F')) && + ((value.Text[value.Offset + 1] == 'a') || (value.Text[value.Offset + 1] == 'A')) && + ((value.Text[value.Offset + 2] == 'l') || (value.Text[value.Offset + 2] == 'L')) && + ((value.Text[value.Offset + 3] == 's') || (value.Text[value.Offset + 3] == 'S')) && + ((value.Text[value.Offset + 4] == 'e') || (value.Text[value.Offset + 4] == 'E')); + return isSpellingFalse ? new Nullable(false) : null; + } + + // Anything else is not considered a boolean + default: { + return null; + } + + } + } + + } + +} // namespace Nuclex.Support.Configuration diff --git a/Source/Configuration/ConfigurationFileStore.cs b/Source/Configuration/ConfigurationFileStore.cs new file mode 100644 index 0000000..97f09c5 --- /dev/null +++ b/Source/Configuration/ConfigurationFileStore.cs @@ -0,0 +1,167 @@ +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2014 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +using System; +using System.Collections.Generic; +using System.IO; + +using Nuclex.Support.Parsing; + +namespace Nuclex.Support.Configuration { + + /// Represents an ini- or cfg-like configuration file + /// + /// This class tries its best to preserve the formatting of configuration files. + /// Changing a value will keep the line it appears in intact. + /// + public partial class ConfigurationFileStore : ISettingsStore { + + #region class Category + + /// Stores informations about a category found in the configuration file + private class Category { + + /// Index of the line the category is defined in + public int LineIndex; + + /// Name of the category as a string + public StringSegment CategoryName; + + } + + #endregion // class Category + + #region class Option + + /// Stores informations about an option found in the configuration file + private class Option { + + /// Index of the line the option is defined in + public int LineIndex; + + /// Name of the option as a string + public StringSegment OptionName; + + /// Value of the option as a string + public StringSegment OptionValue; + + } + + #endregion // class Option + + /// Initializes a new, empty configuration file + public ConfigurationFileStore() { + this.lines = new List(); + this.categories = new List(); + this.options = new List