Files
ntpa/Ntp.Config/ConfigurationBase.cs
T
2016-04-10 11:50:35 +02:00

417 lines
13 KiB
C#

//
// ConfigurationBase.cs
//
// Author:
// Carsten Sonne Larsen <cs@innolan.dk>
//
// Copyright (c) 2013-2016 Carsten Sonne Larsen
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
namespace Ntp.Config
{
public abstract class ConfigurationBase : IEnumerable
{
private readonly string configName;
private readonly int indentLevel;
protected ConfigurationBase(string configName, int indentLevel)
{
this.configName = configName;
this.indentLevel = indentLevel;
}
/// <summary>
/// Gets the name of this configuration config.
/// </summary>
/// <value>The name of the configuration.</value>
public string ConfigName
{
get { return configName; }
}
protected int IndentLevel
{
get { return indentLevel; }
}
#region IEnumerable
protected abstract IEnumerable<Object> Items { get; }
IEnumerator IEnumerable.GetEnumerator()
{
return Items.GetEnumerator();
}
#endregion
#region Error Handling
private static StringBuilder errors = new StringBuilder();
protected int IndentChars = 4;
public static string Errors
{
get { return errors.ToString(); }
}
internal static void ClearErrors()
{
errors = new StringBuilder();
}
protected string ConfigText(string[] settings, IEnumerable<Object> values)
{
var valueList = new List<Object>(values);
string indentHeader = String.Empty.PadLeft(IndentLevel*IndentChars, ' ');
string indentContent = String.Empty.PadLeft((IndentLevel + 1)*IndentChars, ' ');
var text = new StringBuilder();
text.AppendLine();
text.Append(indentHeader);
text.AppendFormat("{0} {1}", settings[0], ConfigName);
text.Append(ConfigName != String.Empty ? " {" : "{");
text.AppendLine();
for (int i = 1; i < settings.Length; i++)
{
if (valueList[i] == null || valueList[i].ToString() == String.Empty)
continue;
if (valueList[i] is IList)
{
var collection = valueList[i] as IEnumerable;
foreach (object item in collection)
{
text.Append(item);
}
}
else if (valueList[i] is ConfigurationBase)
{
text.Append(valueList[i]);
}
else
{
object value = valueList [i];
if (value is bool) {
value = (int)((bool)value ? (int)1 : (int)0);
}
text.Append(indentContent);
text.AppendFormat("{0} {1}", settings[i], value);
text.AppendLine();
}
}
text.Append(indentHeader);
text.AppendLine("}");
return text.ToString();
}
protected static void ConfigError(string errorText)
{
errors.AppendLine(errorText);
}
#endregion
protected static ConfigurationBlock FindSingleBlock(string name, ConfigurationBlock block)
{
return FindSingleBlock(name, block.Lines, block.IndentLevel + 1);
}
protected static ConfigurationBlock FindSingleBlock(string name, string[] lines, int indentLevel, int start = 0)
{
bool found = false;
while (!found)
{
start = FindLine(start, lines, '{');
if (start == -1)
return null;
found = lines[start].Trim().StartsWith(name + " ");
}
int end = FindLine(start, lines, '}', '{');
// No ending symbol
if (end == -1)
{
ConfigError("End of block not found in " + name);
return null;
}
var block = new List<string>(end - start + 1);
for (int c = start; c < end + 1; c++)
block.Add(lines[c]);
return new ConfigurationBlock(start, block.ToArray(), indentLevel);
}
protected static ConfigurationBlock[] FindBlocks(string name, ConfigurationBlock block)
{
return FindBlocks(name, block.Lines, block.IndentLevel);
}
protected static ConfigurationBlock[] FindBlocks(string name, string[] lines, int indentLevel)
{
int start = 0;
var blocks = new List<ConfigurationBlock>();
ConfigurationBlock block;
do
{
block = FindSingleBlock(name, lines, indentLevel + 1, start);
if (block != null)
{
blocks.Add(block);
start = block.Offset;
}
} while (block != null);
return blocks.ToArray();
}
private static int FindLine(int startLine, string[] lines, char searchChar, char indentChar = (char) 0)
{
if (startLine >= lines.Length - 1)
return -1;
bool found = false;
int i = startLine;
int indent = 1;
do
{
i++;
if (indentChar != (char) 0 && lines[i].IndexOf(indentChar) != -1)
indent++;
else if (lines[i].IndexOf(searchChar) != -1)
{
indent--;
found = true;
}
} while ((!found || indent != 0) && i < lines.Length - 1);
if (i == lines.Length - 1 && (!found || indent != 0))
return -1;
return i;
}
protected static OptionSet GetOptions(IEnumerable<String> options, IEnumerable<String> lines)
{
if (options == null || lines == null)
return null;
OptionSet result = new OptionSet();
foreach (string option in options)
result.Add(option, String.Empty);
foreach (string optionLine in lines)
{
string line = optionLine.Trim();
if (line.StartsWith("#"))
continue;
int pos = line.IndexOf(' ');
if (pos == -1)
continue;
string value = line.Substring(pos, line.Length - pos).Trim();
foreach (string option in options)
{
if (line.StartsWith(option + " "))
{
result[option] = value;
break;
}
}
}
return result;
}
protected static IEnumerable<String> GetMultiOption(string option, ConfigurationBlock block)
{
return GetMultiOption(option, block.Lines);
}
protected static List<String> GetMultiOption(string option, string[] lines)
{
var result = new List<string>();
foreach (string line in lines)
{
string currentLine = line.Trim ();
if (!currentLine.StartsWith(option)) continue;
int pos = currentLine.IndexOf(' ');
if (pos == -1)
continue;
if (currentLine.Substring(0, pos).Trim() != option)
continue;
string value = currentLine.Substring(pos, currentLine.Length - pos).Trim();
result.Add(value);
}
return result;
}
protected static string GetOptionConfigName(
Dictionary<String, String> options,
string option,
string configPath,
bool mandatory,
string defaultValue = null)
{
string value = GetOptionString(options, option, configPath, mandatory, "DEFAULT CONFIG");
return value.Replace("{", String.Empty).Trim();
}
protected static string GetOptionString(
Dictionary<String, String> options,
string option,
string configPath,
bool mandatory,
string defaultValue = null)
{
if (options.ContainsKey (option) && options [option] != String.Empty) {
return options [option];
}
if (mandatory) {
ConfigError (String.Format (
"No value for setting {0} in section {1} was specified.",
option, configPath));
}
return defaultValue ?? String.Empty;
}
protected static Int32 GetOptionInteger(
Dictionary<String, String> options,
string option,
string configPath,
bool mandatory,
int defaultValue = 0)
{
if (!options.ContainsKey (option) || options [option].Trim () == String.Empty) {
if (mandatory) {
ConfigError (String.Format (
"No value for setting {0} in section {1} was specified.",
option, configPath));
}
return defaultValue;
}
int ivalue;
if (!Int32.TryParse (options [option].Trim (), out ivalue)) {
ivalue = defaultValue;
ConfigError (String.Format (
"Invalid integer value for setting {0} in section {1}.",
option, configPath));
}
return ivalue;
}
protected static Boolean GetOptionBoolean(
Dictionary<String, String> options,
string option,
string configPath,
bool mandatory,
bool defaultValue = false)
{
if (!options.ContainsKey (option) || options [option].Trim () == String.Empty) {
if (mandatory) {
ConfigError (String.Format (
"No value for setting {0} in section {1} was specified.",
option, configPath));
}
return defaultValue;
}
string value = options [option].Trim ();
if (value.ToLower() == "true" || value == "1")
return true;
if (value.ToLower() == "false" || value == "0")
return false;
ConfigError (String.Format (
"Invalid boolean value for setting {0} in section {1}.",
option, configPath));
return false;
}
protected static Double GetOptionDouble(
Dictionary<String, String> options,
string option,
string configPath,
bool mandatory,
double defaultValue = 0.0)
{
if (!options.ContainsKey (option) || options [option].Trim () == String.Empty) {
if (mandatory) {
ConfigError (String.Format (
"No value for setting {0} in section {1} was specified.",
option, configPath));
}
return defaultValue;
}
double dvalue;
if (!Double.TryParse (options [option].Trim (), out dvalue)) {
dvalue = defaultValue;
ConfigError (String.Format (
"Invalid numeric value for setting {0} in section {1}.",
option, configPath));
}
return dvalue;
}
}
}