// Copyright 2005-2015 Giacomo Stelluti Scala & Contributors. All rights reserved. See License.md in the project root for license information. using System; using System.Collections.Generic; using System.IO; using System.Linq; using CommandLine.Core; using CommandLine.Text; using CSharpx; using RailwaySharp.ErrorHandling; namespace CommandLine { /// /// Provides methods to parse command line arguments. /// public class Parser : IDisposable { private bool disposed; private readonly ParserSettings settings; private static readonly Lazy DefaultParser = new Lazy( () => new Parser(new ParserSettings { HelpWriter = Console.Error })); /// /// Initializes a new instance of the class. /// public Parser() { settings = new ParserSettings { Consumed = true }; } /// /// Initializes a new instance of the class, /// configurable with using a delegate. /// /// The delegate used to configure /// aspects and behaviors of the parser. public Parser(Action configuration) { if (configuration == null) throw new ArgumentNullException("configuration"); settings = new ParserSettings(); configuration(settings); settings.Consumed = true; } internal Parser(ParserSettings settings) { this.settings = settings; this.settings.Consumed = true; } /// /// Finalizes an instance of the class. /// ~Parser() { Dispose(false); } /// /// Gets the singleton instance created with basic defaults. /// public static Parser Default { get { return DefaultParser.Value; } } /// /// Gets the instance that implements in use. /// public ParserSettings Settings { get { return settings; } } /// /// Parses a string array of command line arguments constructing values in an instance of type . /// Grammar rules are defined decorating public properties with appropriate attributes. /// /// Type of the target instance built with parsed value. /// A array of command line arguments, normally supplied by application entry point. /// A containing an instance of type with parsed values /// and a sequence of . /// Thrown if one or more arguments are null. public ParserResult ParseArguments(IEnumerable args) { if (args == null) throw new ArgumentNullException("args"); var factory = typeof(T).IsMutable() ? Maybe.Just>(Activator.CreateInstance) : Maybe.Nothing>(); return MakeParserResult( InstanceBuilder.Build( factory, (arguments, optionSpecs) => Tokenize(arguments, optionSpecs, settings), args, settings.NameComparer, settings.CaseInsensitiveEnumValues, settings.ParsingCulture, settings.AutoHelp, settings.AutoVersion, settings.AllowMultiInstance, HandleUnknownArguments(settings.IgnoreUnknownArguments)), settings); } /// /// Parses a string array of command line arguments constructing values in an instance of type . /// Grammar rules are defined decorating public properties with appropriate attributes. /// /// Type of the target instance built with parsed value. /// A delegate used to initialize the target instance. /// A array of command line arguments, normally supplied by application entry point. /// A containing an instance of type with parsed values /// and a sequence of . /// Thrown if one or more arguments are null. public ParserResult ParseArguments(Func factory, IEnumerable args) { if (factory == null) throw new ArgumentNullException("factory"); if (!typeof(T).IsMutable()) throw new ArgumentException("factory"); if (args == null) throw new ArgumentNullException("args"); return MakeParserResult( InstanceBuilder.Build( Maybe.Just(factory), (arguments, optionSpecs) => Tokenize(arguments, optionSpecs, settings), args, settings.NameComparer, settings.CaseInsensitiveEnumValues, settings.ParsingCulture, settings.AutoHelp, settings.AutoVersion, settings.AllowMultiInstance, HandleUnknownArguments(settings.IgnoreUnknownArguments)), settings); } /// /// Parses a string array of command line arguments for verb commands scenario, constructing the proper instance from the array of types supplied by . /// Grammar rules are defined decorating public properties with appropriate attributes. /// The must be applied to types in the array. /// /// A array of command line arguments, normally supplied by application entry point. /// A array used to supply verb alternatives. /// A containing the appropriate instance with parsed values as a /// and a sequence of . /// Thrown if one or more arguments are null. /// Thrown if array is empty. /// All types must expose a parameterless constructor. It's strongly recommended to use a generic overload. public ParserResult ParseArguments(IEnumerable args, params Type[] types) { if (args == null) throw new ArgumentNullException("args"); if (types == null) throw new ArgumentNullException("types"); if (types.Length == 0) throw new ArgumentOutOfRangeException("types"); return MakeParserResult( InstanceChooser.Choose( (arguments, optionSpecs) => Tokenize(arguments, optionSpecs, settings), types, args, settings.NameComparer, settings.CaseInsensitiveEnumValues, settings.ParsingCulture, settings.AutoHelp, settings.AutoVersion, settings.AllowMultiInstance, HandleUnknownArguments(settings.IgnoreUnknownArguments)), settings); } /// /// Frees resources owned by the instance. /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } private static Result, Error> Tokenize( IEnumerable arguments, IEnumerable optionSpecs, ParserSettings settings) { return settings.GetoptMode ? GetoptTokenizer.ConfigureTokenizer( settings.NameComparer, settings.IgnoreUnknownArguments, settings.EnableDashDash, settings.PosixlyCorrect)(arguments, optionSpecs) : Tokenizer.ConfigureTokenizer( settings.NameComparer, settings.IgnoreUnknownArguments, settings.EnableDashDash)(arguments, optionSpecs); } private static ParserResult MakeParserResult(ParserResult parserResult, ParserSettings settings) { return DisplayHelp( parserResult, settings.HelpWriter, settings.MaximumDisplayWidth); } private static ParserResult DisplayHelp(ParserResult parserResult, TextWriter helpWriter, int maxDisplayWidth) { parserResult.WithNotParsed( errors => Maybe.Merge(errors.ToMaybe(), helpWriter.ToMaybe()) .Do((_, writer) => writer.Write(HelpText.AutoBuild(parserResult, maxDisplayWidth))) ); return parserResult; } private static IEnumerable HandleUnknownArguments(bool ignoreUnknownArguments) { return ignoreUnknownArguments ? Enumerable.Empty().Concat(ErrorType.UnknownOptionError) : Enumerable.Empty(); } private void Dispose(bool disposing) { if (disposed) return; if (disposing) { if (settings != null) settings.Dispose(); disposed = true; } } } }