From b68568be3abadebde1452c8edcb06653a006a3e5 Mon Sep 17 00:00:00 2001 From: "U-WALDRENNACH\\haraldwolff" Date: Wed, 18 Nov 2020 00:04:57 +0100 Subject: [PATCH] Initial Commit --- .gitignore | 41 +++++++++ Argument.cs | 39 ++++++++ ArgumentContainer.cs | 182 +++++++++++++++++++++++++++++++++++++ FieldArgument.cs | 50 ++++++++++ IArgument.cs | 14 +++ PropertyArgument.cs | 50 ++++++++++ StaticArgumentAttribute.cs | 16 ++++ ln.application.csproj | 19 ++++ 8 files changed, 411 insertions(+) create mode 100644 .gitignore create mode 100644 Argument.cs create mode 100644 ArgumentContainer.cs create mode 100644 FieldArgument.cs create mode 100644 IArgument.cs create mode 100644 PropertyArgument.cs create mode 100644 StaticArgumentAttribute.cs create mode 100644 ln.application.csproj 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 + + + + + + + + + +