JD2022-TU1/main/tools/framework/JD.TeaBoxAddinSystem/Bootstrap/Arguments.cs

270 lines
7.5 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using JD.Collections;
using JD.Collections.Extensions;
namespace JD.TeaBoxAddinSystem.Bootstrap
{
/// <summary>
/// Holds a list of command-line arguments
/// </summary>
[Serializable]
public class Arguments
{
#region Variables
private static readonly char[] ms_allowedPrefixes = { '/', '\\', '-' };
private static readonly char[] ms_allowedEqualSymbols = { '=', ':' };
/// <summary>
/// The separator used by default to illustrate switches usage.
/// </summary>
internal const char MainSwitchChar = '-';
private readonly MultiDictionary<string, ArgumentSwitch> m_switches = new MultiDictionary<string, ArgumentSwitch>(StringComparer.OrdinalIgnoreCase);
private readonly List<ArgumentParameter> m_parameters = new List<ArgumentParameter>();
private readonly Argument[] m_allArguments;
#endregion
#region Constructor
/// <summary>
/// Constructor.
/// </summary>
/// <param name="args"></param>
public Arguments(params string[] args)
{
List<Argument> cleanedArguments = new List<Argument>();
foreach (var argument in GetTrimmedArguments(args))
{
ArgumentSwitch argumentSwitch = ExtractSwitch(argument);
if (argumentSwitch != null)
{
m_switches.Add(argumentSwitch.Name, argumentSwitch);
cleanedArguments.Add(argumentSwitch);
}
else
{
ArgumentParameter parameter = new ArgumentParameter(argument);
m_parameters.Add(parameter);
cleanedArguments.Add(parameter);
}
}
m_allArguments = cleanedArguments.ToArray();
}
#endregion
#region Properties
/// <summary>
/// Lists the parameters and the switches in order they are declared.
/// </summary>
public IList<Argument> AllArguments
{
get
{
return m_allArguments.AsReadOnly();
}
}
/// <summary>
/// Returns true if the arguments list is empty.
/// </summary>
public bool IsEmpty
{
get
{
return m_allArguments.Length == 0;
}
}
/// <summary>
/// Gets a list of switches with a given <paramref name="argumentName"/>.
/// </summary>
/// <param name="argumentName">Name of the switches.</param>
/// <returns>The switches</returns>
public ICollection<ArgumentSwitch> this[string argumentName]
{
get
{
return m_switches[argumentName].AsReadOnly();
}
}
/// <summary>
/// Gets all the parameters in the arguments
/// </summary>
public IList<ArgumentParameter> Parameters
{
get
{
return m_parameters.AsReadOnly();
}
}
/// <summary>
/// Gets all the switches in the arguments.
/// </summary>
public IEnumerable<ArgumentSwitch> Switches
{
get
{
return m_switches.Values;
}
}
public int Count
{
get
{
return m_allArguments.Length;
}
}
#endregion
#region Methods
/// <summary>
/// Returns true if the arguments contains the specified switch.
/// </summary>
/// <param name="switchName"></param>
/// <returns></returns>
public bool ContainsSwitch(string switchName)
{
return m_switches.ContainsKey(switchName);
}
public bool TryGetSwitchValue(string switchName, out string value)
{
value = null;
if (ContainsSwitch(switchName))
{
value = this[switchName].FirstOrDefault().Value;
return true;
}
return false;
}
/// <summary>
/// Returns the first switch with the given <paramref name="switchName"/>.
/// </summary>
/// <param name="switchName"></param>
/// <returns></returns>
public ArgumentSwitch FirstSwitch(string switchName)
{
return this[switchName].FirstOrDefault();
}
/// <summary>
/// Overriden.
/// </summary>
/// <returns></returns>
public override string ToString()
{
return $"[Arguments: {Parameters.Count} parameters, {new List<ArgumentSwitch>(Switches).Count} switches]";
}
private static IEnumerable<string> GetTrimmedArguments(string[] arguments)
{
foreach (var argument in arguments)
{
string trimmedArgument = TrimSpacesAndQuotes(argument);
if (!String.IsNullOrEmpty(trimmedArgument))
{
yield return trimmedArgument;
}
}
}
private static string TrimSpacesAndQuotes(string value)
{
string trimmed = value.Trim();
// Extract quotes and double quotes
if (trimmed.Length > 2 && ((trimmed[0] == '"' && trimmed[trimmed.Length - 1] == '"') ||
(trimmed[0] == '\'' && trimmed[trimmed.Length - 1] == '\'')))
{
return trimmed.Substring(1, trimmed.Length - 2).Trim();
}
return trimmed;
}
private static ArgumentSwitch ExtractSwitch(string argument)
{
int nameStart = FindSwitchNameStart(argument);
if (nameStart <= 0)
{
return null;
}
int nameEnd = FindSwitchNameEnd(nameStart, argument);
if (nameEnd == nameStart)
{
return null;
}
if (nameEnd == -1)
{
return new ArgumentSwitch(argument.Substring(nameStart));
}
int valueStart = FindSwitchValueStart(nameEnd, argument);
if (valueStart == -1)
{
return new ArgumentSwitch(argument.Substring(nameStart, nameEnd - nameStart));
}
string name = argument.Substring(nameStart, nameEnd - nameStart);
string value = argument.Substring(valueStart);
return new ArgumentSwitch(name, value);
}
private static int FindSwitchNameStart(string argument)
{
return FindSequenceEnd(ms_allowedPrefixes, 0, argument);
}
private static int FindSwitchNameEnd(int startIndex, string argument)
{
return argument.IndexOfAny(ms_allowedEqualSymbols, startIndex);
}
private static int FindSwitchValueStart(int startIndex, string argument)
{
return FindSequenceEnd(ms_allowedEqualSymbols, startIndex, argument);
}
private static int FindSequenceEnd(char[] anyOf, int startIndex, string value)
{
for (int i = startIndex; i < value.Length; i++)
{
char character = value[i];
if (!anyOf.Contains(character))
{
return i;
}
}
return -1;
}
#endregion
}
}