/// <summary> /// Creates a new CommandLineParserException /// </summary> /// <param name="message">The error message</param> /// <param name="innerException">The inner exception</param> /// <param name="Position">The argument position</param> public CommandLineParserException(string message, Exception innerException, CommandLineArgumentPosition Position) : base(message, innerException) { this.Position = Position; }
/// <summary> /// Parses a set of arguments /// </summary> /// <param name="args">The arguments to parse</param> /// <returns>The arguments</returns> public IEnumerable<CommandLineArgument> ParseArguments(IEnumerable<string> args) { var soMap = options.Where(x => x.ShortOption != default(char)).ToDictionary(x => ShortOptionStylizer != null ? ShortOptionStylizer(x.ShortOption) : x.ShortOption); var loMap = options.Where(x => x.LongOption != null).ToDictionary(x => LongOptionStylizer?.Invoke(x.LongOption) ?? x.LongOption); var option = default(CommandLineOption); var buffer = new StringBuilder(); var state = ParseState.Head; var argbuf = new List<string>(); var pos = new CommandLineArgumentPosition(0, 0); int pchr = int.MinValue; foreach (var chr in new StringArrayEnumerable(args, -1, -2)) { switch (pchr) { case -1: pos.Argument++; pos.Index = 0; break; case int.MinValue: break; default: pos.Index++; break; } pchr = chr; switch (state) { #region "Discard" case ParseState.Discard: switch (chr) { case -1: state = ParseState.Head; break; default: break; } break; #endregion #region "Head" case ParseState.Head: switch (chr) { case -1: argbuf.Add(""); if (option != null && option.MaximumArguments == argbuf.Count) { yield return new CommandLineArgument(option, argbuf.ToArray(), pos.Argument - argbuf.Count); option = null; argbuf.Clear(); } break; case -2: if (argbuf.Count > 0 || option != null) { yield return new CommandLineArgument(option, argbuf.ToArray(), pos.Argument - argbuf.Count); option = null; argbuf.Clear(); } break; case '-': state = ParseState.FirstDash; break; default: state = ParseState.Body; buffer.Clear(); buffer.Append((char)chr); break; } break; #endregion #region "FirstDash" case ParseState.FirstDash: switch (chr) { case -1: argbuf.Add("-"); if (option != null && option.MaximumArguments == argbuf.Count) { yield return new CommandLineArgument(option, argbuf.ToArray(), pos.Argument - argbuf.Count); option = null; argbuf.Clear(); } state = ParseState.Head; break; case '-': if (option != null) { yield return new CommandLineArgument(option, argbuf.ToArray(), pos.Argument - argbuf.Count); option = null; argbuf.Clear(); } state = ParseState.SecondDash; break; default: if (argbuf.Count > 0 || option != null) { yield return new CommandLineArgument(option, argbuf.ToArray(), pos.Argument - argbuf.Count); option = null; argbuf.Clear(); } state = ParseState.SingleDash; if (!soMap.TryGetValue((char)chr, out option)) { var ex = new CommandLineParserException(string.Format("Unknown short option: {0}", (char)chr), pos); if (Error != null) Error(this, new CommandLineParser.ErrorEventArgs(ex)); else throw ex; } break; } break; #endregion #region "SingleDash" case ParseState.SingleDash: switch (chr) { case -1: if (option != null && option.MaximumArguments == 0) { yield return new CommandLineArgument(option, pos.Argument); option = null; } state = ParseState.Head; break; case '=': if (option == null) { buffer.Clear(); state = ParseState.Discard; } else if (option.MaximumArguments != 0) { buffer.Clear(); state = ParseState.Equals; } else { yield return new CommandLineArgument(option, pos.Argument); option = null; state = ParseState.Discard; } break; default: if (option != null) yield return new CommandLineArgument(option); if (!soMap.TryGetValue((char)chr, out option)) { var ex = new CommandLineParserException(string.Format("Unknown short option: {0}", (char)chr), pos); if (Error != null) Error(this, new CommandLineParser.ErrorEventArgs(ex)); else throw ex; } break; } break; #endregion #region "Equals" case ParseState.Equals: switch (chr) { case -1: yield return new CommandLineArgument(option, buffer.ToString(), pos.Argument - 1); option = null; state = ParseState.Head; break; default: buffer.Append((char)chr); break; } break; #endregion #region "SecondDash" case ParseState.SecondDash: switch (chr) { case -1: buffer.Clear(); state = ParseState.Tail; break; default: if (argbuf.Count > 0 || option != null) { yield return new CommandLineArgument(option, argbuf.ToArray(), pos.Argument - argbuf.Count); option = null; argbuf.Clear(); } buffer.Clear(); buffer.Append((char)chr); state = ParseState.DoubleDash; break; } break; #endregion #region "DoubleDash" case ParseState.DoubleDash: switch (chr) { case -1: if (loMap.TryGetValue(buffer.ToString(), out option)) { if (option.MaximumArguments == 0) { yield return new CommandLineArgument(option, pos.Argument); option = null; } } else { var ex = new CommandLineParserException(string.Format("Unknown long option: {0}", buffer.ToString()), pos); if (Error != null) Error(this, new CommandLineParser.ErrorEventArgs(ex)); else throw ex; } state = ParseState.Head; break; case '=': if (loMap.TryGetValue(buffer.ToString(), out option)) { if (option.MaximumArguments != 0) { buffer.Clear(); state = ParseState.Equals; } else { yield return new CommandLineArgument(option, pos.Argument); option = null; state = ParseState.Discard; } } else { var ex = new CommandLineParserException(string.Format("Unknown long option: {0}", buffer.ToString()), pos); if (Error != null) Error(this, new CommandLineParser.ErrorEventArgs(ex)); else throw ex; buffer.Clear(); state = ParseState.Discard; } break; default: buffer.Append((char)chr); break; } break; #endregion #region "Tail" case ParseState.Tail: switch (chr) { case -2: if (argbuf.Count > 0) { yield return new CommandLineArgument(option, argbuf.ToArray(), pos.Argument - argbuf.Count); option = null; argbuf.Clear(); } break; case -1: argbuf.Add(buffer.ToString()); buffer.Clear(); break; default: buffer.Append((char)chr); break; } break; #endregion #region "Body" case ParseState.Body: switch (chr) { case -1: argbuf.Add(buffer.ToString()); if (option != null && option.MaximumArguments == argbuf.Count) { yield return new CommandLineArgument(option, argbuf.ToArray(), pos.Argument - argbuf.Count); option = null; argbuf.Clear(); } state = ParseState.Head; break; default: buffer.Append((char)chr); break; } break; #endregion } } }
/// <summary> /// Creates a new CommandLineParserException /// </summary> /// <param name="Position">The argument position</param> public CommandLineParserException(CommandLineArgumentPosition Position) : base() { this.Position = Position; }