270 lines
7.5 KiB
C#
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
|
|
}
|
|
}
|