commit b68568be3abadebde1452c8edcb06653a006a3e5 Author: U-WALDRENNACH\haraldwolff Date: Wed Nov 18 00:04:57 2020 +0100 Initial Commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bf793ed --- /dev/null +++ b/.gitignore @@ -0,0 +1,41 @@ +# Autosave files +*~ + +# build +[Oo]bj/ +[Bb]in/ +packages/ +TestResults/ + +# globs +Makefile.in +*.DS_Store +*.sln.cache +*.suo +*.cache +*.pidb +*.userprefs +*.usertasks +config.log +config.make +config.status +aclocal.m4 +install-sh +autom4te.cache/ +*.user +*.tar.gz +tarballs/ +test-results/ +Thumbs.db +.vs/ + +# Mac bundle stuff +*.dmg +*.app + +# resharper +*_Resharper.* +*.Resharper + +# dotCover +*.dotCover diff --git a/Argument.cs b/Argument.cs new file mode 100644 index 0000000..9f89148 --- /dev/null +++ b/Argument.cs @@ -0,0 +1,39 @@ +using System; + +namespace ln.application +{ + public class Argument : IArgument + { + public char OptionName { get; } + public String LongOptionName { get; } + public string HelpString { get; } + + public bool HasArgument { get; set; } + + public string Value { get; set; } = null; + + public int IntegerValue => int.Parse(Value); + public double DoubleValue => double.Parse(Value); + + public Argument(char optionNameName, string longOptionNameName) + { + OptionName = optionNameName; + LongOptionName = longOptionNameName; + } + public Argument(char optionNameName, string longOptionNameName, int defaultValue) + : this(optionNameName, longOptionNameName, defaultValue.ToString()) { } + public Argument(char optionNameName, string longOptionNameName, double defaultValue) + : this(optionNameName, longOptionNameName, defaultValue.ToString()) { } + + public Argument(char optionNameName, string longOptionNameName, string defaultValue) + { + OptionName = optionNameName; + LongOptionName = longOptionNameName; + Value = defaultValue; + } + + + + } + +} \ No newline at end of file diff --git a/ArgumentContainer.cs b/ArgumentContainer.cs new file mode 100644 index 0000000..a479d14 --- /dev/null +++ b/ArgumentContainer.cs @@ -0,0 +1,182 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace ln.application +{ + /// + /// Argument container. + /// + /// + /// This class parses command line arguments to a list of predefined well known arguments. + /// Remaining arguments will be found in AdditionalArguments. + /// + /// ArgumentContainer also provides a global command line option: + /// --change-static typename fieldname value + /// It may be used multiple times on the command line. + /// It will load the type referenced by the qualified name typename and try to set the static field fieldname to value. + /// value will be casted to field type via Convert.ChangeType(...) + /// + public class ArgumentContainer + { + private Dictionary shortOptionArguments = new Dictionary(); + private Dictionary longOptionArguments = new Dictionary(); + + public ArgumentContainer() + { + } + public ArgumentContainer(IEnumerable argumentDefinitions) + { + AddRange(argumentDefinitions); + } + + public ArgumentContainer(Type type) + { + AddStaticOptions(type); + } + + public IArgument this[string optionName] => longOptionArguments[optionName]; + public IArgument this[char option] => shortOptionArguments[option]; + + public bool Contains(string optionName) =>longOptionArguments.ContainsKey(optionName); + public bool Contains(char option) => shortOptionArguments.ContainsKey(option); + + public ArgumentContainer AddRange(IEnumerable arguments) + { + foreach (IArgument argument in arguments) + Add(argument); + + return this; + } + + public ArgumentContainer Add(IArgument argument) + { + if (argument.OptionName > 0) + shortOptionArguments.Add(argument.OptionName,argument); + if (argument.LongOptionName != null) + longOptionArguments.Add(argument.LongOptionName, 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 string[] Parse(IEnumerable args) + { + List unusedArguments = new List(); + + Queue q = new Queue(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 if (Contains(aname)) + { + IArgument argument = this[aname]; + argument.Value = argument.HasArgument ? q.Dequeue() : ""; + } else + { + unusedArguments.Add("--" + aname); + } + } + else + { + foreach (char option in currentOption.Substring(1)) + { + IArgument argument = this[option]; + argument.Value = argument.HasArgument ? q.Dequeue() : ""; + } + } + } + else + { + unusedArguments.Add(currentOption); + } + } + + return unusedArguments.ToArray(); + } + public void Parse(ref string[] args) => args = Parse(args); + + public static string[] ApplyArguments(string[] arguments) + { + ArgumentContainer argumentContainer = new ArgumentContainer(); + argumentContainer.AddStaticOptions(typeof(T)); + return argumentContainer.Parse(arguments); + } + public static void ApplyArguments(ref string[] arguments) + { + arguments = ApplyArguments(arguments); + } + + public static string[] ApplyArguments(T instance,string[] arguments) + { + ArgumentContainer argumentContainer = new ArgumentContainer(); + argumentContainer.AddOptions(instance); + return argumentContainer.Parse(arguments); + } + public static void ApplyArguments(T instance,ref string[] arguments) + { + arguments = ApplyArguments(instance, arguments); + } + + public ArgumentContainer AddStaticOptions(Type type) + { + foreach (FieldInfo fieldInfo in type.GetFields(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public)) + { + if (fieldInfo.GetCustomAttribute() != null) + Add(new FieldArgument(fieldInfo, fieldInfo.GetCustomAttribute())); + } + foreach (PropertyInfo propertyInfo in type.GetProperties(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public)) + { + if (propertyInfo.GetCustomAttribute() != null) + Add(new PropertyArgument(propertyInfo, propertyInfo.GetCustomAttribute())); + } + + return this; + } + public ArgumentContainer AddOptions(T instance) + { + foreach (FieldInfo fieldInfo in typeof(T).GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)) + { + if (fieldInfo.GetCustomAttribute() != null) + Add(new FieldArgument(instance, fieldInfo)); + } + foreach (PropertyInfo propertyInfo in typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)) + { + if (propertyInfo.GetCustomAttribute() != null) + Add(new PropertyArgument(instance, propertyInfo)); + } + + return this; + } + + public ArgumentContainer AddStaticOptions() => AddStaticOptions(typeof(T)); + + + public void ChangeStatic(string typeName,string fieldname,string value) + { + Type type = Type.GetType(typeName); + FieldInfo fieldInfo = type.GetField(fieldname, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + + object castValue = Convert.ChangeType(value, fieldInfo.FieldType); + fieldInfo.SetValue(null,castValue); + } + } +} diff --git a/FieldArgument.cs b/FieldArgument.cs new file mode 100644 index 0000000..562f5f5 --- /dev/null +++ b/FieldArgument.cs @@ -0,0 +1,50 @@ +using System.Reflection; +using ln.type; + +namespace ln.application +{ + public class FieldArgument : IArgument + { + public FieldInfo FieldInfo { get; } + public object Instance { get;} + + public FieldArgument(FieldInfo fieldInfo) + :this(null, fieldInfo, fieldInfo.GetCustomAttribute()) + {} + public FieldArgument(object instance,FieldInfo fieldInfo) + :this(instance, fieldInfo, fieldInfo.GetCustomAttribute()) + {} + + public FieldArgument(FieldInfo fieldInfo, StaticArgumentAttribute staticArgumentAttribute) + :this(null,fieldInfo,staticArgumentAttribute){} + public FieldArgument(object instance,FieldInfo fieldInfo, StaticArgumentAttribute staticArgumentAttribute) + { + FieldInfo = fieldInfo; + OptionName = staticArgumentAttribute?.Option ?? (char)0; + LongOptionName = staticArgumentAttribute?.LongOption ?? fieldInfo.Name; + HelpString = staticArgumentAttribute?.HelpString ?? ""; + HasArgument = fieldInfo.FieldType != typeof(bool); + Instance = instance; + } + + public char OptionName { get; } + public string LongOptionName { get; } + public bool HasArgument { get; } + public string HelpString { get; } + public string Value + { + get => FieldInfo.GetValue(Instance)?.ToString(); + set + { + if (HasArgument) + { + FieldInfo.SetValue(Instance, Cast.To(value, FieldInfo.FieldType)); + } + else + { + FieldInfo.SetValue(Instance, true); + } + } + } + } +} \ No newline at end of file diff --git a/IArgument.cs b/IArgument.cs new file mode 100644 index 0000000..002ec5b --- /dev/null +++ b/IArgument.cs @@ -0,0 +1,14 @@ +namespace ln.application +{ + public interface IArgument + { + char OptionName { get; } + string LongOptionName { get; } + + bool HasArgument { get; } + + string HelpString { get; } + + string Value { get; set; } + } +} \ No newline at end of file diff --git a/PropertyArgument.cs b/PropertyArgument.cs new file mode 100644 index 0000000..f9db910 --- /dev/null +++ b/PropertyArgument.cs @@ -0,0 +1,50 @@ +using System.Reflection; +using ln.type; + +namespace ln.application +{ + public class PropertyArgument : IArgument + { + public PropertyInfo PropertyInfo { get; } + public object Instance { get;} + + public PropertyArgument(PropertyInfo propertyInfo) + :this(null, propertyInfo, propertyInfo.GetCustomAttribute()) + {} + public PropertyArgument(object instance, PropertyInfo propertyInfo) + :this(instance, propertyInfo, propertyInfo.GetCustomAttribute()) + {} + + public PropertyArgument(PropertyInfo propertyInfo, StaticArgumentAttribute staticArgumentAttribute) + :this(null, propertyInfo, staticArgumentAttribute){} + public PropertyArgument(object instance,PropertyInfo propertyInfo, StaticArgumentAttribute staticArgumentAttribute) + { + PropertyInfo = propertyInfo; + OptionName = staticArgumentAttribute?.Option ?? (char)0; + LongOptionName = staticArgumentAttribute?.LongOption ?? propertyInfo.Name; + HelpString = staticArgumentAttribute?.HelpString ?? ""; + HasArgument = propertyInfo.PropertyType != typeof(bool); + Instance = instance; + } + + public char OptionName { get; } + public string LongOptionName { get; } + public bool HasArgument { get; } + public string HelpString { get; } + public string Value + { + get => PropertyInfo.GetValue(Instance)?.ToString(); + set + { + if (HasArgument) + { + PropertyInfo.SetValue(Instance, Cast.To(value, PropertyInfo.PropertyType)); + } + else + { + PropertyInfo.SetValue(Instance, true); + } + } + } + } +} \ No newline at end of file diff --git a/StaticArgumentAttribute.cs b/StaticArgumentAttribute.cs new file mode 100644 index 0000000..e3ded78 --- /dev/null +++ b/StaticArgumentAttribute.cs @@ -0,0 +1,16 @@ +using System; + +namespace ln.application +{ + public class StaticArgumentAttribute : Attribute + { + public char Option { get; set; } + public string LongOption { get; set; } + + public string HelpString { get; set; } + + public StaticArgumentAttribute() + {} + + } +} \ No newline at end of file diff --git a/ln.application.csproj b/ln.application.csproj new file mode 100644 index 0000000..b53d418 --- /dev/null +++ b/ln.application.csproj @@ -0,0 +1,19 @@ + + + + netcoreapp3.1 + true + 0.1.0 + Harald Wolff-Thobaben + 0.0.1.0 + 0.0.1.0 + + + + + + + + + +