private static IEnumerable<Pattern> ParseLong(Tokens tokens, ICollection<Option> options) { // long ::= '--' chars [ ( ' ' | '=' ) chars ] ; var p = new StringPartition(tokens.Move(), "="); var longName = p.LeftString; Debug.Assert(longName.StartsWith("--")); var value = (p.NoSeparatorFound) ? null : new ValueObject(p.RightString); var similar = options.Where(o => o.LongName == longName).ToList(); if (tokens.ThrowsInputError && similar.Count == 0) { // If not exact match similar = options.Where(o => !String.IsNullOrEmpty(o.LongName) && o.LongName.StartsWith(longName)).ToList(); } if (similar.Count > 1) { // Might be simply specified ambiguously 2+ times? throw tokens.CreateException(string.Format("{0} is not a unique prefix: {1}?", longName, string.Join(", ", similar.Select(o => o.LongName)))); } Option option = null; if (similar.Count < 1) { var argCount = p.Separator == "=" ? 1 : 0; option = new Option(null, longName, argCount); options.Add(option); if (tokens.ThrowsInputError) option = new Option(null, longName, argCount, argCount != 0 ? value : new ValueObject(true)); } else { option = new Option(similar[0].ShortName, similar[0].LongName, similar[0].ArgCount, similar[0].Value); if (option.ArgCount == 0) { if (value != null) throw tokens.CreateException(option.LongName + " must not have an argument"); } else { if (value == null) { if (tokens.Current() == null || tokens.Current() == "--") throw tokens.CreateException(option.LongName + " requires an argument"); value = new ValueObject(tokens.Move()); } } if (tokens.ThrowsInputError) option.Value = value ?? new ValueObject(true); } return new[] {option}; }
private static IEnumerable<Pattern> ParseShorts(Tokens tokens, ICollection<Option> options) { // shorts ::= '-' ( chars )* [ [ ' ' ] chars ] ; var token = tokens.Move(); Debug.Assert(token.StartsWith("-") && !token.StartsWith("--")); var left = token.TrimStart(new[] {'-'}); var parsed = new List<Pattern>(); while (left != "") { var shortName = "-" + left[0]; left = left.Substring(1); var similar = options.Where(o => o.ShortName == shortName).ToList(); Option option = null; if (similar.Count > 1) { throw tokens.CreateException(string.Format("{0} is specified ambiguously {1} times", shortName, similar.Count)); } if (similar.Count < 1) { option = new Option(shortName, null, 0); options.Add(option); if (tokens.ThrowsInputError) { option = new Option(shortName, null, 0, new ValueObject(true)); } } else { // why is copying necessary here? option = new Option(shortName, similar[0].LongName, similar[0].ArgCount, similar[0].Value); ValueObject value = null; if (option.ArgCount != 0) { if (left == "") { if (tokens.Current() == null || tokens.Current() == "--") { throw tokens.CreateException(shortName + " requires argument"); } value = new ValueObject(tokens.Move()); } else { value = new ValueObject(left); left = ""; } } if (tokens.ThrowsInputError) option.Value = value ?? new ValueObject(true); } parsed.Add(option); } return parsed; }