Created
April 17, 2013 07:00
-
-
Save Larry57/5402309 to your computer and use it in GitHub Desktop.
Command line parser in one cs file.
http://codeblocks.codeplex.com/SourceControl/changeset/view/101246#1887400
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* This package contains a powerful, declarative command-line parsing system in a single .cs file. | |
| * You can include this in any project with almost zero footprint and very easy/readable usage, | |
| * as shown below. More switch types, including generic ones are coming soon. Visit the project | |
| * page for a sample of how to use this handy package. Part of Code Blocks (http://codeblocks.codeplex.com) | |
| */ | |
| using System; | |
| using System.Collections.Generic; | |
| using System.Linq; | |
| using System.Text; | |
| using System.Text.RegularExpressions; | |
| using System.ComponentModel; | |
| using System.IO; | |
| using System.Reflection; | |
| static class CommandLine | |
| { | |
| private interface IValType | |
| { | |
| Type GetValType { get; } | |
| } | |
| public abstract class SwitchBase | |
| { | |
| protected SwitchBase() | |
| { | |
| } | |
| public string Name | |
| { | |
| get; | |
| protected set; | |
| } | |
| public string ShortForm | |
| { | |
| get; | |
| protected set; | |
| } | |
| public string Description { get; set; } | |
| public object DefaultValue { get; set; } | |
| public bool Optional { get; protected set; } | |
| public abstract int InvokeHandler(IEnumerable<object> values); | |
| } | |
| public abstract class SwitchBase<T> : SwitchBase, IValType // Class that encapsulates switch data. | |
| { | |
| protected SwitchBase(string name, Action<IEnumerable<T>> handler, string shortForm) | |
| { | |
| Name = name; | |
| Handler = handler; | |
| ShortForm = shortForm; | |
| } | |
| protected SwitchBase(string name, Action<IEnumerable<T>> handler) | |
| { | |
| Name = name; | |
| Handler = handler; | |
| ShortForm = null; | |
| } | |
| public Action<IEnumerable<T>> Handler | |
| { | |
| get; | |
| private set; | |
| } | |
| public override int InvokeHandler(IEnumerable<object> values) | |
| { | |
| Handler(values.Cast<T>()); | |
| return Optional ? 0 : 1; | |
| } | |
| new public T DefaultValue | |
| { | |
| get { return (T)base.DefaultValue; } | |
| set { base.DefaultValue = value; } | |
| } | |
| Type IValType.GetValType | |
| { | |
| get { return typeof(T); } | |
| } | |
| } | |
| public sealed class Switch : SwitchBase<string> | |
| { | |
| public Switch(string name, Action<IEnumerable<string>> handler, string shortForm) | |
| : base(name, handler, shortForm) | |
| { | |
| } | |
| public Switch(string name, Action<IEnumerable<string>> handler) | |
| : base(name, handler) | |
| { | |
| } | |
| new public bool Optional | |
| { | |
| get { return base.Optional; } | |
| set { base.Optional = value; } | |
| } | |
| } | |
| public sealed class OptionalSwitch : SwitchBase<string> | |
| { | |
| public OptionalSwitch(string name, Action<IEnumerable<string>> handler, string shortForm) | |
| : base(name, handler, shortForm) | |
| { | |
| base.Optional = true; | |
| } | |
| public OptionalSwitch(string name, Action<IEnumerable<string>> handler) | |
| : base(name, handler) | |
| { | |
| base.Optional = true; | |
| } | |
| new bool Optional { get { return true; } } | |
| } | |
| public sealed class MandatorySwitch : SwitchBase<string> | |
| { | |
| public MandatorySwitch(string name, Action<IEnumerable<string>> handler, string shortForm) | |
| : base(name, handler, shortForm) | |
| { | |
| base.Optional = false; | |
| } | |
| public MandatorySwitch(string name, Action<IEnumerable<string>> handler) | |
| : base(name, handler) | |
| { | |
| base.Optional = false; | |
| } | |
| new bool Optional { get { return false; } } | |
| } | |
| public sealed class Switch<T> : SwitchBase<T> | |
| { | |
| public Switch(string name, Action<IEnumerable<T>> handler, string shortForm) | |
| : base(name, handler, shortForm) | |
| { | |
| } | |
| public Switch(string name, Action<IEnumerable<T>> handler) | |
| : base(name, handler) | |
| { | |
| } | |
| } | |
| public sealed class OptionalSwitch<T> : SwitchBase<T> | |
| { | |
| public OptionalSwitch(string name, Action<IEnumerable<T>> handler, string shortForm) | |
| : base(name, handler, shortForm) | |
| { | |
| base.Optional = true; | |
| } | |
| public OptionalSwitch(string name, Action<IEnumerable<T>> handler) | |
| : base(name, handler) | |
| { | |
| base.Optional = true; | |
| } | |
| new bool Optional { get { return true; } } | |
| } | |
| public sealed class MandatorySwitch<T> : SwitchBase<T> | |
| { | |
| public MandatorySwitch(string name, Action<IEnumerable<T>> handler, string shortForm) | |
| : base(name, handler, shortForm) | |
| { | |
| base.Optional = false; | |
| } | |
| public MandatorySwitch(string name, Action<IEnumerable<T>> handler) | |
| : base(name, handler) | |
| { | |
| base.Optional = false; | |
| } | |
| new bool Optional { get { return false; } } | |
| } | |
| /* The regex that extracts names and comma-separated values for switches | |
| in the form (<switch>[="value 1",value2,...])+ */ | |
| private static readonly Regex ArgRegex = | |
| new Regex(@"(?<name>[^=]+)=?((?<quoted>\""?)(?<value>(?(quoted)[^\""]+|[^,]+))\""?,?)*", | |
| RegexOptions.Compiled | RegexOptions.CultureInvariant | | |
| RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase); | |
| private const string NameGroup = "name"; // Names of capture groups | |
| private const string ValueGroup = "value"; | |
| private static string BuildUsageString(this string[] args, params SwitchBase[] switches) | |
| { | |
| var builder = new StringBuilder(); | |
| builder.AppendFormat("Usage is {0} ", Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().CodeBase)); | |
| var argUsages = from s in switches | |
| select string.Format("{0}=<{1} {2}>", s.ShortForm == null ? s.Name : s.Name + "|" + s.ShortForm, | |
| s.Description ?? string.Empty, | |
| s.DefaultValue == null ? string.Empty : "(" + s.DefaultValue + ")"); | |
| builder.Append(string.Join(" ", argUsages)); | |
| return builder.ToString(); | |
| } | |
| public static bool Process(this string[] args, Action<string> printUsage, params SwitchBase[] switches) | |
| { | |
| return Process(args, () => printUsage(BuildUsageString(args, switches)), switches); | |
| } | |
| public static bool Process(this string[] args, Action printUsage, params SwitchBase[] switches) | |
| { | |
| /* Run through all matches in the argument list and if any of the switches | |
| match, get the values and invoke the handler we were given. We do a Sum() | |
| here for 2 reasons; a) To actually run the handlers | |
| and b) see if any were invoked at all (each returns 1 if invoked). | |
| If none were invoked, we simply invoke the printUsage handler. */ | |
| if ((from arg in args | |
| from Match match in ArgRegex.Matches(arg) | |
| from s in switches | |
| let destType = (s as IValType).GetValType | |
| where match.Success && | |
| ((string.Compare(match.Groups[NameGroup].Value, s.Name, true) == 0) || | |
| (string.Compare(match.Groups[NameGroup].Value, s.ShortForm, true) == 0)) | |
| select s.InvokeHandler( | |
| from val in match.Groups[ValueGroup].Value.Split(',') | |
| let typeConverter = TypeDescriptor.GetConverter(destType) | |
| where ((typeConverter != null) && (typeConverter.CanConvertFrom(val.GetType()))) | |
| select typeConverter.ConvertFrom(val) | |
| )).Sum() < (from s in switches select s.Optional ? 0 : 1).Sum()) | |
| { | |
| printUsage(); // We didn't find some mandatory switches | |
| return false; | |
| } | |
| else | |
| return true; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment