ln.types/ArgumentContainer.cs

208 lines
7.2 KiB
C#

using System;
using System.Collections.Generic;
using System.Collections;
using System.Reflection;
using ln.logging;
using System.ComponentModel;
namespace ln.types
{
public class Argument
{
public char Short { get; }
public String Long { get; }
public bool NeedsValue { get; }
public bool HasValue => Value != null;
public String Value { get; set; }
public int IntegerValue => int.Parse(Value);
public double DoubleValue => double.Parse(Value);
public bool IsSet { get; set; }
public Argument(char shortName, string longName)
{
Short = shortName;
Long = longName;
NeedsValue = false;
}
public Argument(char shortName, string longName, int defaultValue)
: this(shortName, longName, defaultValue.ToString()) { }
public Argument(char shortName, string longName, double defaultValue)
: this(shortName, longName, defaultValue.ToString()) { }
public Argument(char shortName, string longName, string defaultValue)
{
Short = shortName;
Long = longName;
NeedsValue = true;
Value = defaultValue;
}
}
/// <summary>
/// Argument container.
/// </summary>
/// <remarks>
/// This class parses command line arguments to a list of predefined well known arguments.
/// Remaining arguments will be found in <c>AdditionalArguments</c>.
///
/// <c>ArgumentContainer</c> also provides a global command line option:
/// --change-static <para>typename</para> <para>fieldname</para> <para>value</para>
/// It may be used multiple times on the command line.
/// It will load the type referenced by the qualified name <para>typename</para> and try to set the static field <para>fieldname</para> to <para>value</para>.
/// <para>value</para> will be casted to field type via Convert.ChangeType(...)
/// </remarks>
public class ArgumentContainer
{
List<Argument> arguments;
List<String> additionalArguments;
public string[] AdditionalArguments => additionalArguments.ToArray();
public ArgumentContainer()
{
arguments = new List<Argument>();
additionalArguments = new List<string>();
}
public ArgumentContainer(IEnumerable<Argument> argumentDefinitions)
: this()
{
arguments.AddRange(argumentDefinitions);
}
public Argument this[string longName]
{
get
{
if (longName == null)
throw new ArgumentNullException(nameof(longName));
foreach (Argument argument in arguments)
{
if (longName.Equals(argument.Long))
return argument;
}
throw new KeyNotFoundException();
}
}
public Argument this[char shortName]
{
get
{
if (shortName == 0)
throw new ArgumentNullException(nameof(shortName));
foreach (Argument argument in arguments)
{
if (shortName.Equals(argument.Short))
return argument;
}
throw new KeyNotFoundException();
}
}
public bool Contains(string longName)
{
if (longName != null)
foreach (Argument argument in arguments)
{
if (longName.Equals(argument.Long))
return true;
}
return false;
}
public bool Contains(char shortName)
{
if (shortName == (char)0)
return false;
foreach (Argument argument in arguments)
{
if (shortName.Equals(argument.Short))
return true;
}
return false;
}
public ArgumentContainer Add(Argument argument)
{
if (Contains(argument.Short) || Contains(argument.Long))
throw new ArgumentException(nameof(argument),String.Format("0x{0:x} / {1}",(int)argument.Short,argument.Long));
arguments.Add(argument);
return this;
}
public ArgumentContainer Add(char shortName) => Add(new Argument(shortName, null));
public ArgumentContainer Add(string longName) => Add(new Argument((char)0, longName));
public ArgumentContainer Add(char shortName, string longName) => Add(new Argument(shortName, longName));
public ArgumentContainer Add(char shortName, string longName, string defaultValue) => Add(new Argument(shortName, longName, defaultValue));
public ArgumentContainer Add(int shortName, string longName, string defaultValue) => Add(new Argument((char)shortName, longName, defaultValue));
public void Parse(IEnumerable<string> args)
{
Queue<string> q = new Queue<string>(args);
while (q.Count > 0)
{
string currentOption = q.Dequeue();
if (currentOption[0].Equals('-'))
{
if (currentOption[1].Equals('-'))
{
String aname = currentOption.Substring(2);
if (aname.Equals("change-static"))
{
string typeName = q.Dequeue();
string fieldName = q.Dequeue();
string value = q.Dequeue();
ChangeStatic(typeName, fieldName, value);
}
else
{
Argument argument = this[aname];
argument.IsSet = true;
if (argument.NeedsValue)
argument.Value = q.Dequeue();
}
}
else
{
foreach (char option in currentOption.Substring(1))
{
Argument argument = this[option];
argument.IsSet = true;
if (argument.NeedsValue)
argument.Value = q.Dequeue();
}
}
}
else
{
additionalArguments.Add(currentOption);
}
}
}
public void ChangeStatic(string typeName,string fieldname,string value)
{
Type type = Type.GetType(typeName);
Logging.Log(LogLevel.INFO, "ArgumentContainer: ChangeStatic: Type: {0}",type);
FieldInfo fieldInfo = type.GetField(fieldname, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
Logging.Log(LogLevel.INFO, "ArgumentContainer: ChangeStatic: Field: {0} {1}", fieldname, fieldInfo);
object castValue = Convert.ChangeType(value, fieldInfo.FieldType);
fieldInfo.SetValue(null,castValue);
}
}
}