public override bool TryGetOption <T>(string name, out T value, T @default = default) { OptionRun matchingOption = _run.Options.FirstOrDefault(r => r.Option.HasName(name)); if (matchingOption is null) { value = default; return(false); } if (matchingOption.Occurrences == 0) { value = matchingOption.Assigned ? (T)matchingOption.Value : @default; return(true); } object resolvedValue = matchingOption.Value; if (resolvedValue != null) { Type valueType = resolvedValue.GetType(); if (!typeof(T).IsAssignableFrom(valueType)) { throw new InvalidOperationException($"The option's value is of type '{valueType.FullName}' is not assignable to the specified type of '{typeof(T).FullName}'."); } } value = (T)resolvedValue; return(true); }
/// <summary> /// Resolves an <see cref="Option" />'s value based on it's usage details. See the /// <see cref="OptionRun.GetOptionValueType(Option)" /> method for details on how the /// resolution is done. /// </summary> /// <param name="optionRun">The <see cref="OptionRun" /> instance, whose option to resolve.</param> /// <returns>The value of the option.</returns> private static object ResolveOptionParameterValues(OptionRun optionRun) { switch (optionRun.ValueType) { case OptionValueType.Count: return(optionRun.Occurrences); case OptionValueType.Flag: return(optionRun.Occurrences > 0); case OptionValueType.List: IList list = optionRun.CreateCollection(optionRun.Parameters.Count); foreach (string parameter in optionRun.Parameters) { list.Add(optionRun.ResolveValue(parameter)); } return(list); case OptionValueType.Object: return(optionRun.ResolveValue(optionRun.Parameters[0])); } throw new ParserException(-1, "Should never reach here"); }
/// <inheritdoc/> public override IEnumerable <string> IdentifyTokens(IEnumerable <string> tokens, IReadOnlyList <OptionRun> options, ArgGrouping grouping) { ArgumentType previousType = ArgumentType.NotSet; ArgumentType currentType = ArgumentType.NotSet; foreach (string token in tokens) { VerifyCommandLineGrouping(previousType, currentType, grouping); previousType = currentType; var optionMatch = OptionPattern.Match(token); if (!optionMatch.Success) { currentType = ArgumentType.Argument; yield return(token); } else { currentType = ArgumentType.Option; string specifiedOptionName = optionMatch.Groups[groupnum : 1].Value; // Find the corresponding option run for the specified option name. // If not found, throw a parse exception. OptionRun availableOption = options.SingleOrDefault(or => or.Option.HasName(specifiedOptionName)); if (availableOption is null) { throw new ParserException(ParserException.Codes.InvalidOptionSpecified, string.Format(Messages.InvalidOptionSpecified, specifiedOptionName)); } // Increase the number of occurrences of the option run. availableOption.Occurrences += 1; // If no option parameters are specified, we're done with this option. // Continue the loop to process the next token. if (token.Length == specifiedOptionName.Length + 1) { continue; } // Option name and its parameters must be separated by a colon. // If not, throw a parse exception. if (token[specifiedOptionName.Length + 1] != ':') { throw new ParserException(ParserException.Codes.InvalidOptionParameterSpecifier, string.Format(Messages.InvalidOptionParameterSpecifier, specifiedOptionName)); } // Match any parameters and add to the option run's Parameters property. var parameterMatches = OptionParameterPattern.Matches(token, optionMatch.Length + 1); foreach (Match parameterMatch in parameterMatches) { string value = parameterMatch.Groups[groupnum : 1].Value; if (value.StartsWith(",", StringComparison.OrdinalIgnoreCase)) { value = value.Remove(startIndex: 0, count: 1); } availableOption.Parameters.Add(value); } } } VerifyCommandLineGrouping(previousType, currentType, grouping); }
/// <inheritdoc/> public override IEnumerable <string> IdentifyTokens(IEnumerable <string> tokens, IReadOnlyList <OptionRun> options, ArgGrouping grouping) { OptionRun currentOption = null; bool forceArguments = false; foreach (string token in tokens) { if (token == "--") { forceArguments = true; continue; } if (forceArguments) { yield return(token); continue; } Match optionMatch = OptionPattern.Match(token); // If the token is not an option and we are not iterating over the parameters of an // option, then the token is an argument. if (!optionMatch.Success) { // If we're processing an option (currentOption != null), then it's an argument. // Otherwise, it's a parameter on the current option. if (currentOption is null) { yield return(token); } else { currentOption.Parameters.Add(token); } } else { bool isShortOption = optionMatch.Groups[1].Value.Length == 1; string optionName = optionMatch.Groups[2].Value; string parameterValue = optionMatch.Groups[3].Value; bool isParameterSpecified = !string.IsNullOrEmpty(parameterValue); // If multiple short options are specified as a single combined option, then none // of them can have parameters. if (isShortOption && optionName.Length > 1 && isParameterSpecified) { throw new ParserException(-1, $"Cannot specify a parameter for the combined option {optionName}."); } // Get the specified option names. // If a short option name is specified and it has multiple characters, each // character is a short name. string[] optionNames = isShortOption && optionName.Length > 1 ? optionName.Select(c => c.ToString()).ToArray() : new[] { optionName }; // Add each option to its corresponding option run. foreach (string name in optionNames) { OptionRun matchingOption = options.SingleOrDefault(or => or.Option.HasName(name)); if (matchingOption is null) { throw new ParserException(ParserException.Codes.InvalidOptionSpecified, string.Format(Messages.InvalidOptionSpecified, optionName)); } // Increase the number of occurrences of the option matchingOption.Occurrences += 1; } // If only one option was specified (and not a combined short option set), we deal // with the parameters now. if (optionNames.Length == 1) { // We know its option run exists, so use Single here. OptionRun matchingOption = options.Single(or => or.Option.HasName(optionNames[0])); // If the parameter was specified in the same token with a "=" symbol, then // that is the only parameter we can allow. // Add it and proceed with the next token. if (isParameterSpecified) { matchingOption.Parameters.Add(parameterValue); currentOption = null; } // Otherwise, mark the current option as this one and process all subsequent // tokens as parameters until we encounter another option or we've reached the // max limit of parameters for this option. else { currentOption = matchingOption; } } else { currentOption = null; } } // If we're on an option (currentOption != null) and the number of parameters has // reached the maximum allowed, then we can stop handling that option by setting // currentOption to null so that the next arg will be treated as a new option or // argument. if (currentOption != null && currentOption.Parameters.Count >= currentOption.Option.Usage.MaxParameters) { currentOption = null; } } }