/* TShock, a server mod for Terraria Copyright (C) 2011-2018 Pryaxis & TShock Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ 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); i++) { string flag = source[i].ToLowerInvariant(); string argument = null; if (string.IsNullOrWhiteSpace(flag)) { continue; } 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; } } } }