#region Apache License 2.0 /* Nuclex .NET Framework Copyright (C) 2002-2024 Markus Ewald / Nuclex Development Labs Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #endregion // Apache License 2.0 using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Text; namespace Nuclex.Support.Settings { /// 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. The parser also takes /// as much data from a line as it can - anything to the left of an equals sign /// becomes the name, anything to the right (excluding comments) becomes the value. /// /// /// To access the contents of a configuration file, simply parse it and use it like /// you would any other settings store: /// /// /// /// // # Settings.ini /// // message = hello world ; the usual... /// // show message = true /// ISettingsStore settings; /// using(var reader = new StreamReader("settings.ini")) { /// settings = ConfigurationFile.Parse(reader); /// } /// /// if(settings.Get<bool>(null, "show message")) { /// Console.WriteLine(settings.Get<string>(null, "message")); /// } /// /// /// /// It's usually a good idea to keep an application and all of its required files /// together, whether it's code or data, but platforms often have their own conventions: /// /// /// /// Operating System /// Convention /// /// /// Linux /// /// System-wide configuration goes into /etc/<appname>/, user-specific /// configuration goes into ~/.<appname>/ while static configuration that is /// known at build time resides with the application in /opt/<appname>/ /// /// /// /// Windows /// /// System-wide configuration goes into %ProgramData%, user-specific configuration /// has no real place (try %AppData%/<appname>/ if you want to hide it from /// the user, %UserProfile%/Documents/<appname> if the user should see it) /// and static configuration resides with your application /// in %ProgramFiles%/<appname>/. /// /// /// /// MacOS /// /// System-wide configuration goes into /etc/<appname>/, user-specific /// configuration goes into /Users/<username>/.<appname>/ while static /// configuration resides with the application in /Applications/<appname>/ /// /// /// /// public partial class ConfigurationFileStore : ISettingsStore { #region class Category /// Stores informations about a category found in the configuration file private class Category { /// Name of the category as a string public StringSegment CategoryName; /// Lookup table for the options in this category public IDictionary OptionLookup; /// Lines this category and its options consist of public IList Lines; } #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.options = new List