mirror of
https://bitbucket.org/anguist/ntpa
synced 2026-09-26 19:00:40 +00:00
417 lines
13 KiB
C#
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;
|
|
}
|
|
}
|
|
} |