using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
namespace TShockAPI.CLI
{
///
/// A simple command-line parser for retrieving basic information from a command-line. Array types are not supported
///
public class CommandLineParser
{
private List _flags = new List();
private Dictionary _results = new Dictionary();
private string[] _source;
///
/// Resets the CommandLineParser, removing any results and flags, and clearing the source
///
///
public CommandLineParser Reset()
{
_flags.Clear();
_results.Clear();
_source = null;
return this;
}
///
/// Adds a flag to be parsed
///
/// The flag to be added
/// Whether or not the flag is followed by an argument
public CommandLineParser AddFlag(string flag, bool noArgs = false)
{
FlagSet flags = new FlagSet(flag) { NoArgs = noArgs };
return AddFlags(flags);
}
///
/// Adds a flag to be parsed, with the given callback being invoked with the flag's argument when it is found.
/// The callback's parameter is the argument passed to the flag
///
///
///
///
public CommandLineParser AddFlag(string flag, Action callback)
{
FlagSet flags = new FlagSet(flag) { callback = callback };
return AddFlags(flags);
}
///
/// Adds a flag to be parsed, with the given callback being invoked when the flag is found.
/// This method assumes the flag has no arguments
///
///
///
///
public CommandLineParser AddFlag(string flag, Action callback)
{
FlagSet flags = new FlagSet(flag) { NoArgs = true, callback = callback };
return AddFlags(flags);
}
///
/// Adds a range of flags to be parsed
///
/// The FlagSet to be added
///
public CommandLineParser AddFlags(FlagSet flags)
{
if (_flags.Contains(flags))
{
return this;
}
_flags.Add(flags);
return this;
}
///
/// Adds a range of flags to be parsed, with the given callback being invoked with the flag's argument when it is found.
/// The callback's parameter is the argument passed to the flag
///
/// The FlagSet to be added
/// An Action with a single string parameter. This parameter is the value passed to the flag
///
public CommandLineParser AddFlags(FlagSet flags, Action callback)
{
flags.callback = callback;
return AddFlags(flags);
}
///
/// Adds a range of flags to be parsed, with the given callback being invoked when the flag's argument is found.
/// This method assumes the flag has no arguments
///
/// The FlagSet to be added
/// An Action with no parameters.
///
public CommandLineParser AddFlags(FlagSet flags, Action callback)
{
flags.callback = callback;
flags.NoArgs = true;
return AddFlags(flags);
}
///
/// Adds a callback after a flag's parsing has been completed.
/// This method automatically attaches the callback to the last added flag
///
/// An Action with no parameters.
///
public CommandLineParser After(Action callback)
{
FlagSet flags = _flags.Last();
flags.continuation = callback;
return this;
}
///
/// Gets the result of a FlagSet, cast to the given type parameter. Array types are not supported
///
///
///
///
public T Get(FlagSet flags)
{
if (!_results.ContainsKey(flags))
{
return default(T);
}
object result = _results[flags];
Type t = typeof(T);
if (t == typeof(string))
{
if (result == null)
{
return (T)(object)string.Empty;
}
return (T)result;
}
if (t.IsValueType)
{
TypeConverter tc = TypeDescriptor.GetConverter(t);
return (T)tc.ConvertFromString(result.ToString());
}
return (T)Activator.CreateInstance(t, result);
}
///
/// Parses the given source for flags registered with the parser
///
///
///
public CommandLineParser ParseFromSource(string[] source)
{
_source = source;
for (int i = 0; i < (source.Length - 1 == 0 ? 1 : source.Length - 1); i++)
{
string flag = source[i].ToLowerInvariant();
string argument = null;
if (i + 1 < source.Length)
{
argument = source[i + 1];
}
FlagSet flags = _flags.FirstOrDefault(f => f.Contains(flag));
if (flags == null)
{
continue;
}
if (flags.NoArgs)
{
if (flags.callback != null)
{
((Action)flags.callback).Invoke();
}
else
{
_results.Add(flags, true);
}
}
else
{
if (flags.callback != null)
{
((Action)flags.callback).Invoke(argument);
}
else
{
_results.Add(flags, argument);
}
}
flags.continuation?.Invoke();
}
return this;
}
///
/// Gets the result of a flag, cast to the given type parameter. Array types are not supported
///
///
///
///
public T Get(string flag)
{
FlagSet flags = _flags.FirstOrDefault(f => f.Contains(flag));
if (flags == null)
{
return default(T);
}
return Get(flags);
}
///
/// Attempts to get the result of a flag, cast to the given type parameter. Array types are not supported
///
///
///
///
///
public bool TryGet(string flag, out T value)
{
FlagSet flags = _flags.FirstOrDefault(f => f.Contains(flag));
if (flags == null)
{
value = default(T);
return false;
}
return TryGet(flags, out value);
}
///
/// Attempts to get the result of a FlagSet, cast to the given type parameter. Array types are not supported
///
///
///
///
///
public bool TryGet(FlagSet flags, out T value)
{
object result = _results[flags];
if (result == null)
{
//Null result shouldn't happen, but return false if it does
value = default(T);
return false;
}
Type t = typeof(T);
//Strings get special handling because the result object is a string
if (t == typeof(string))
{
if (result == null)
{
//Null strings shouldn't happen, but return false if it does
value = default(T);
return false;
}
value = (T)result;
return true;
}
//Value types get converted with a TypeConverter
if (t.IsValueType)
{
try
{
TypeConverter tc = TypeDescriptor.GetConverter(t);
value = (T)tc.ConvertFrom(result);
return true;
}
catch
{
value = default(T);
return false;
}
}
try
{
//Reference types get created with an Activator
value = (T)Activator.CreateInstance(t, result);
return true;
}
catch
{
value = default(T);
return false;
}
}
}
}