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($"{longName} is not a unique prefix: {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('-'); 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; if (similar.Count > 1) { throw tokens.CreateException($"{shortName} is specified ambiguously {similar.Count} times"); } if (similar.Count < 1) { option = new Option(shortName); 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); }