/// <summary> /// Parses <paramref name="pattern"/>, calling appropriate overloads /// in <paramref name="parser"/> /// </summary> /// <param name="pattern">Pattern to parse</param> /// <param name="parser">Parser to call back</param> public static void Parse( WildcardPattern pattern, WildcardPatternParser parser) { parser.BeginWildcardPattern(pattern); bool previousCharacterIsAnEscape = false; bool previousCharacterStartedBracketExpression = false; bool insideCharacterRange = false; StringBuilder characterRangeContents = null; StringBuilder characterRangeOperators = null; foreach (char c in pattern.Pattern) { if (insideCharacterRange) { if (c == ']' && !previousCharacterStartedBracketExpression && !previousCharacterIsAnEscape) { // An unescaped closing square bracket closes the character set. In other // words, there are no nested square bracket expressions // This is different than the POSIX spec // (at http://www.opengroup.org/onlinepubs/9699919799/functions/fnmatch.html), // but we are keeping this behavior for back-compatibility. insideCharacterRange = false; parser.AppendBracketExpression(characterRangeContents.ToString(), characterRangeOperators.ToString(), pattern.Pattern); characterRangeContents = null; characterRangeOperators = null; } else if (c != pattern.EscapeCharacter || previousCharacterIsAnEscape) { characterRangeContents.Append(c); characterRangeOperators.Append((c == '-') && !previousCharacterIsAnEscape ? '-' : ' '); } previousCharacterStartedBracketExpression = false; } else { if (c == '*' && !previousCharacterIsAnEscape) { parser.AppendAsterix(); } else if (c == '?' && !previousCharacterIsAnEscape) { parser.AppendQuestionMark(); } else if (c == '[' && !previousCharacterIsAnEscape) { insideCharacterRange = true; characterRangeContents = new StringBuilder(); characterRangeOperators = new StringBuilder(); previousCharacterStartedBracketExpression = true; } else if (c != pattern.EscapeCharacter || previousCharacterIsAnEscape) { parser.AppendLiteralCharacter(c); } } previousCharacterIsAnEscape = (c == pattern.EscapeCharacter) && (!previousCharacterIsAnEscape); } if (insideCharacterRange) { throw NewWildcardPatternException(pattern.Pattern); } if (previousCharacterIsAnEscape) { if (!pattern.Pattern.Equals($"{pattern.EscapeCharacter}", StringComparison.Ordinal)) // Win7 backcompatibility requires treating '`' pattern as '' pattern when this code was used with PowerShell. { parser.AppendLiteralCharacter(pattern.Pattern[pattern.Pattern.Length - 1]); } } parser.EndWildcardPattern(); }
/// <summary> /// Called from <see cref="Parse"/> method to indicate /// the beginning of the wildcard pattern. /// Default implementation simply returns. /// </summary> /// <param name="pattern"> /// <see cref="WildcardPattern"/> object that includes both /// the text of the pattern (<see cref="WildcardPattern.Pattern"/>) /// and the pattern options (<see cref="WildcardPattern.Options"/>) /// </param> protected virtual void BeginWildcardPattern(WildcardPattern pattern) { }