private void AddRules(IEnumerable <string> rules, MatchFlags flags, bool loadedFromFile) { var ruleList = GetValidRuleLines(rules, loadedFromFile) .Select(line => new IgnoreRule(line.Pattern, flags, line.LineNumber)); _rules.AddRange(ruleList); }
public MatchState(MatchState parent, int nextSegmentIndex, MatchFlags flags, string segment, MatchedVariable[] variables) { NextSegmentIndex = nextSegmentIndex; Flags = flags; this.parent = parent; this.segment = segment; this.variables = variables; }
/// <summary> /// Create an individual ignore rule for the specified pattern /// </summary> /// <param name="pattern">A glob pattern specifying file(s) this rule should ignore</param> /// <param name="flags">Optional flags determining pattern matching behaviour</param> public IgnoreRule(string pattern, MatchFlags flags = MatchFlags.PATHNAME) { if (Utils.IsNullOrWhiteSpace(pattern)) { throw new ArgumentNullException(nameof(pattern)); } // Keep track of the original pattern before modifications (for display purposes) OriginalPattern = pattern; Pattern = pattern; MatchFlags = flags; // First, let's figure out some things about the pattern and set flags to pass to our match function PatternFlags = PatternFlags.NONE; // If the pattern starts with an exclamation mark, it's a negation pattern // Once we know that, we can remove the exclamation mark (so the pattern behaves just like any other), // then just negate the match result when we return it if (Pattern.StartsWith("!", sc)) { PatternFlags |= PatternFlags.NEGATION; Pattern = Pattern.Substring(1); } // If the pattern starts with a forward slash, it should only match an absolute path if (Pattern.StartsWith("/", sc)) { PatternFlags |= PatternFlags.ABSOLUTE_PATH; Pattern = Pattern.Substring(1); } // If the pattern ends with a forward slash, it should only match a directory // Again though, once we know that we can remove the slash to normalise the pattern if (Pattern.EndsWith("/", sc)) { PatternFlags |= PatternFlags.DIRECTORY; Pattern = Pattern.Substring(0, Pattern.Length - 1); } _wildcardIndex = Pattern.IndexOfAny(new char[] { '*', '[', '?' }); // If CASEFOLD is set, string comparisons should ignore case too if (MatchFlags.HasFlag(MatchFlags.CASEFOLD)) { sc = StringComparison.OrdinalIgnoreCase; } // If PATHNAME is set, single asterisks should not match slashes if (!MatchFlags.HasFlag(MatchFlags.PATHNAME)) { MatchFlags |= MatchFlags.PATHNAME; } // TODO: Currently, we are just setting PATHNAME for every rule, because it seems to match the original behaviour // See here for a clue: https://github.com/git/git/blob/c2c5f6b1e479f2c38e0e01345350620944e3527f/dir.c#L99 }
protected void GetMatchFlagsAndOptions(ContentFlags contentFlags, out MatchFlags matchFlags, out MatchOptions matchOptions) { ContentFlags contentFlags2 = contentFlags & (ContentFlags)51; switch (contentFlags2) { case ContentFlags.SubString: matchOptions = MatchOptions.SubString; break; case ContentFlags.Prefix: matchOptions = MatchOptions.Prefix; break; default: if (contentFlags2 != ContentFlags.PrefixOnWords) { if (contentFlags2 != ContentFlags.ExactPhrase) { matchOptions = MatchOptions.FullString; } else { matchOptions = MatchOptions.ExactPhrase; } } else { matchOptions = MatchOptions.PrefixOnWords; } break; } matchFlags = MatchFlags.Default; if ((contentFlags & ContentFlags.IgnoreCase) != ContentFlags.FullString) { matchFlags |= MatchFlags.IgnoreCase; } if ((contentFlags & ContentFlags.IgnoreNonSpace) != ContentFlags.FullString) { matchFlags |= MatchFlags.IgnoreNonSpace; } if ((contentFlags & ContentFlags.Loose) != ContentFlags.FullString) { matchFlags |= MatchFlags.Loose; } }
private static StringComparison GetStringComparison(MatchFlags flags) { bool flag = MatchFlags.Default != (flags & MatchFlags.IgnoreCase); bool flag2 = MatchFlags.Default != (flags & MatchFlags.IgnoreNonSpace); if (flag && flag2) { return(StringComparison.OrdinalIgnoreCase); } if (!flag && flag2) { return(StringComparison.Ordinal); } if (flag && !flag2) { return(StringComparison.OrdinalIgnoreCase); } return(StringComparison.Ordinal); }
protected ContentFlags GetContentFlags(MatchFlags matchFlags, MatchOptions matchOptions) { ContentFlags contentFlags; switch (matchOptions) { case MatchOptions.SubString: contentFlags = ContentFlags.SubString; goto IL_34; case MatchOptions.Prefix: contentFlags = ContentFlags.Prefix; goto IL_34; case MatchOptions.PrefixOnWords: contentFlags = ContentFlags.PrefixOnWords; goto IL_34; case MatchOptions.ExactPhrase: contentFlags = ContentFlags.ExactPhrase; goto IL_34; } contentFlags = ContentFlags.FullString; IL_34: if ((matchFlags & MatchFlags.IgnoreCase) != MatchFlags.Default) { contentFlags |= ContentFlags.IgnoreCase; } if ((matchFlags & MatchFlags.IgnoreNonSpace) != MatchFlags.Default) { contentFlags |= ContentFlags.IgnoreNonSpace; } if ((matchFlags & MatchFlags.Loose) != MatchFlags.Default) { contentFlags |= ContentFlags.Loose; } return(contentFlags); }
/// <summary> /// Create a list of ignore rules to check paths against /// </summary> /// <param name="rules">A list of glob ignore patterns as strings</param> /// <param name="flags">Optional flags determining pattern matching behaviour</param> public IgnoreList(IEnumerable <string> rules, MatchFlags flags = MatchFlags.PATHNAME) { AddRules(rules, flags); }
/// <summary> /// Create a list of ignore rules to check paths against /// </summary> /// <param name="ignoreFilePath">Path to a text file containing a list of glob ignore patterns as strings</param> /// <param name="flags">Optional flags determining pattern matching behaviour</param> public IgnoreList(string ignoreFilePath, MatchFlags flags = MatchFlags.PATHNAME) { AddRules(ignoreFilePath, flags); }
private static int Match(char[] pattern, char[] text, int p, int t, MatchFlags flags) { int p_len = pattern.Length; int p_EOP = p_len - 1; int t_len = text.Length; int t_EOP = t_len - 1; char p_ch; for (; p < p_len && (p_ch = pattern[p]) != -1; p++, t++) { int match, negated; bool match_slash; char t_ch, prev_ch; if (t == t_len && p_ch != '*') { return(ABORT_ALL); } t_ch = text[t]; if (flags.HasFlag(MatchFlags.CASEFOLD) && Char.IsUpper(t_ch)) { t_ch = Char.ToLower(t_ch); } if (flags.HasFlag(MatchFlags.CASEFOLD) && Char.IsUpper(p_ch)) { p_ch = Char.ToLower(p_ch); } switch (p_ch) { // Escape character: require literal match of next char case '\\': p_ch = pattern[++p]; goto default; // Normal character: literal match default: if (t_ch != p_ch) { return(NOMATCH); } continue; // Match any character except slash case '?': if (t_ch == '/') { return(NOMATCH); } continue; // Match any character unless PATHNAME flag is set, then match any char except slash case '*': // If the *next* character is a star as well... if ((++p) < p_len && pattern[p] == '*') { // Figure out what the character *before* the first star is // (using null char to represent the beginning of the pattern) char pre_star_ch = (p - 2) >= 0 ? pattern[p - 2] : '\0'; // Advance through the pattern until we get to something which *isn't* a star while ((++p) < p_len && pattern[p] == '*') { } // If PATHNAME isn't set, a single star also matches slashes if (!flags.HasFlag(MatchFlags.PATHNAME)) { match_slash = true; } // If the character before the first star is either the beginning of the pattern or a slash, // and the character after the last star is either the end of the pattern or a slash else if ((pre_star_ch == '\0' || pre_star_ch == '/') && (p == p_len || pattern[p] == '/')) { if ((p == p_len || pattern[p] == '/') && Match(pattern, text, p + 1, t, flags) == MATCH) { return(MATCH); } match_slash = true; } else { // The pattern is invalid (double-star wildcards are only valid // if bounded by slashes or beginning/end of line) return(ABORT_MALFORMED); } } else { // It's only a single star, so use PATHNAME to determine whether to match slashes match_slash = !flags.HasFlag(MatchFlags.PATHNAME); } // If we're at the end of the pattern if (p == p_len) { // If there was only one star and PATHNAME was set, match_slash will be false // Trailing "*" matches only if there are no more slash characters if (!match_slash && Array.IndexOf(text, '/', t) != -1) { return(NOMATCH); } // Trailing "**" matches everything return(MATCH); } else if (!match_slash && pattern[p] == '/') { // We're at a slash, so consume the text until the next slash int nextSlashIndex = Array.IndexOf(text, '/', t); // If there aren't any more slashes, this can't be a match if (nextSlashIndex == -1) { return(NOMATCH); } t = nextSlashIndex; break; } // Try to match the remaining text // Each time the match fails, remove the first character from the text and retry while (true) { if (t == t_EOP) { break; } // Try to advance faster when an asterisk is followed by a literal. // We know in this case that the string before the literal must belong to "*". // If match_slash is false, do not look past the first slash as it cannot belong to '*'. if (!IsGlobSpecial(pattern[p])) { p_ch = pattern[p]; if (flags.HasFlag(MatchFlags.CASEFOLD) && Char.IsUpper(p_ch)) { p_ch = Char.ToLower(p_ch); } while (t < t_len && ((t_ch = text[t]) != '/' || match_slash)) { if (flags.HasFlag(MatchFlags.CASEFOLD) && Char.IsUpper(t_ch)) { t_ch = Char.ToLower(t_ch); } if (t_ch == p_ch) { break; } t++; } if (t_ch != p_ch) { return(NOMATCH); } } if ((match = Match(pattern, text, p, t, flags)) != NOMATCH) { if (!match_slash || match != ABORT_TO_STARSTAR) { return(match); } } else if (!match_slash && t_ch == '/') { return(ABORT_TO_STARSTAR); } t_ch = text[++t]; } return(ABORT_ALL); // Match character ranges case '[': p_ch = pattern[++p]; negated = (p_ch == NEGATE_CLASS || p_ch == NEGATE_CLASS2) ? 1 : 0; if (negated == 1) { p_ch = pattern[++p]; } prev_ch = '\0'; match = 0; do { if (p == p_len) { return(ABORT_ALL); } if (p_ch == '\\') { if (++p == p_len) { return(ABORT_ALL); } p_ch = pattern[p]; if (t_ch == p_ch) { match = 1; } } else if (p_ch == '-' && prev_ch != '\0' && p < p_EOP && pattern[p + 1] != ']') { p_ch = pattern[++p]; if (p_ch == '\\') { if (++p == p_len) { return(ABORT_ALL); } p_ch = pattern[p]; } if (t_ch <= p_ch && t_ch >= prev_ch) { match = 1; } else if (flags.HasFlag(MatchFlags.CASEFOLD) && Char.IsLower(t_ch)) { char t_ch_upper = Char.ToUpper(t_ch); if (t_ch_upper <= p_ch && t_ch_upper >= prev_ch) { match = 1; } } p_ch = '\0'; // This makes "prev_ch" get set to 0 } else if (p_ch == '[' && p < p_EOP && pattern[p + 1] == ':') { int s; int i; // SHARED ITERATOR for (s = p + 2; p < p_len && (p_ch = pattern[p]) != ']'; p++) { } if (p == p_EOP) { return(ABORT_ALL); } i = p - s - 1; if (i < 0 || pattern[p - 1] != ':') { // Didn't find ":]", so treat like a normal set p = s - 2; p_ch = '['; if (t_ch == p_ch) { match = 1; } continue; } if (CC_EQ(pattern, s, i, "alnum")) { if (Char.IsLetterOrDigit(t_ch)) { match = 1; } } else if (CC_EQ(pattern, s, i, "alpha")) { if (Char.IsLetter(t_ch)) { match = 1; } } else if (CC_EQ(pattern, s, i, "blank")) { if (Char.IsWhiteSpace(t_ch)) { match = 1; } } else if (CC_EQ(pattern, s, i, "cntrl")) { if (Char.IsControl(t_ch)) { match = 1; } } else if (CC_EQ(pattern, s, i, "digit")) { if (Char.IsDigit(t_ch)) { match = 1; } } // else if (CC_EQ(pattern, s, i, "graph")) // { // if (ISGRAPH(t_ch)) // match = 1; // } else if (CC_EQ(pattern, s, i, "lower")) { if (Char.IsLower(t_ch)) { match = 1; } } // else if (CC_EQ(pattern, s, i, "print")) // { // if (ISPRINT(t_ch)) // match = 1; // } else if (CC_EQ(pattern, s, i, "punct")) { if (Char.IsPunctuation(t_ch)) { match = 1; } } else if (CC_EQ(pattern, s, i, "space")) { if (Char.IsWhiteSpace(t_ch)) { match = 1; } } else if (CC_EQ(pattern, s, i, "upper")) { if (Char.IsUpper(t_ch)) { match = 1; } else if (flags.HasFlag(MatchFlags.CASEFOLD) && Char.IsLower(t_ch)) { match = 1; } } else if (CC_EQ(pattern, s, i, "xdigit")) { if (Char.IsDigit(t_ch) || (Char.ToLower(t_ch) >= 'a' && Char.ToLower(t_ch) <= 'f')) { match = 1; } } else // Malformed [:class:] string { return(ABORT_ALL); } p_ch = '\0'; // This makes "prev_ch" get set to 0 } else if (t_ch == p_ch) { match = 1; } prev_ch = p_ch; } while (p < p_len && (p_ch = pattern[++p]) != ']'); if (match == negated || (flags.HasFlag(MatchFlags.PATHNAME) && t_ch == '/')) { return(NOMATCH); } continue; } } return(t == text.Length ? MATCH : NOMATCH); }
internal static bool HasMatchFlag(this MatchFlags flags, MatchFlags flag) => (flags & flag) != 0;
private QueryFilter BuildTextFilter(PropertyDefinition[] properties, string propertyValue, MatchOptions matchOption, MatchFlags matchFlags) { if (string.IsNullOrEmpty(propertyValue)) { return(null); } if (properties.Length == 1) { return(new TextFilter(properties[0], propertyValue, matchOption, matchFlags)); } if (properties.Length > 1) { QueryFilter[] array = new QueryFilter[properties.Length]; for (int i = 0; i < properties.Length; i++) { array[i] = new TextFilter(properties[i], propertyValue, matchOption, matchFlags); } return(new OrFilter(array)); } return(null); }
internal static int IsMatch(string pattern, string text, MatchFlags flags) { return(Match(pattern.ToCharArray(), text.ToCharArray(), 0, 0, flags)); }
public static int MatchAll(object pattern, object data, out PhpArray matches, MatchFlags flags, int offset) { return Match(pattern, data, out matches, flags, offset, true); }
/// <summary> /// Add multiple rules to the ignore list /// </summary> /// <param name="rules">A list of glob ignore patterns as strings</param> /// <param name="flags">Optional flags determining pattern matching behaviour</param> public void AddRules(IEnumerable <string> rules, MatchFlags flags = MatchFlags.PATHNAME) { AddRules(rules, flags, false); }
/// <summary> /// Create a list of ignore rules to check paths against /// </summary> /// <param name="ignoreFilePath">Path to a text file containing a list of glob ignore patterns as strings</param> /// <param name="flags">Optional flags determining pattern matching behaviour</param> public IgnoreList(string ignoreFilePath, MatchFlags flags = MatchFlags.PATHNAME) { AddRules(File.ReadAllLines(ignoreFilePath), flags); }
public TextFilter(PropertyDefinition property, string text, MatchOptions matchOptions, MatchFlags matchFlags) : base(property, matchOptions, matchFlags) { this.text = text; }
/// <summary> /// Initializes a new instance of the <see cref="IgnoreList"/> class. /// </summary> /// <param name="ignoreFilePath">Path to a text file containing a list of ignore patterns as strings.</param> /// <param name="flags">Optional flags determining pattern matching behaviour.</param> public IgnoreList(string ignoreFilePath, MatchFlags flags = MatchFlags.PATHNAME) =>
/// <summary> /// Initializes a new instance of the <see cref="IgnoreList"/> class. /// </summary> /// <param name="rules">A list of glob ignore patterns as strings.</param> /// <param name="flags">Optional flags determining pattern matching behaviour.</param> public IgnoreList(IEnumerable <string> rules, MatchFlags flags = MatchFlags.PATHNAME) =>
public BinaryFilter(PropertyDefinition property, byte[] binaryData, MatchOptions matchOptions, MatchFlags matchFlags) : base(property, matchOptions, matchFlags) { this.binaryData = binaryData; }
/// <summary> /// Add a rule to the ignore list /// </summary> /// <param name="rule">Glob ignore pattern as string</param> /// <param name="flags">Optional flags determining pattern matching behaviour</param> public void AddRule(string rule, MatchFlags flags = MatchFlags.PATHNAME) { AddRules(new string[] { rule }, flags, false); }
private static MatchResult DoWild(CharPointer p, CharPointer text, MatchFlags flags) { char p_ch; var pattern = p; for ( ; (p_ch = p.Value) != '\0'; text = text.Increment(), p = p.Increment()) { int matched; char t_ch; if ((t_ch = text.Value) == '\0' && p_ch != '*') { return(MatchResult.AbortAll); } if (flags.HasFlag(MatchFlags.CaseFold)) { if (char.IsUpper(t_ch)) { t_ch = char.ToLower(t_ch); } if (char.IsUpper(p_ch)) { p_ch = char.ToLower(p_ch); } } switch (p_ch) { case '\\': p = p.Increment(); p_ch = p.Value; // fallthrough goto default; default: if (t_ch != p_ch) { return(MatchResult.NoMatch); } continue; case '?': if (flags.HasFlag(MatchFlags.PathName) && t_ch == '/') { return(MatchResult.NoMatch); } continue; case '*': p = p.Increment(); bool match_slash; if (p.Value == '*') { var prev_p = p.Increment(-2); p = p.Increment(); while (p.Value == '*') { p.Increment(); } if (!flags.HasFlag(MatchFlags.PathName)) { match_slash = true; } else if ((prev_p.Index < pattern.Index || prev_p.Value == '/') && (p.Value == '\0' || p.Value == '/' || (p.Value == '\\' && p.Increment().Value == '/'))) { if (p.Value == '/' && DoWild(p.Increment(), text, flags) == MatchResult.Match) { return(MatchResult.Match); } match_slash = true; } else { return(MatchResult.AbortMalformed); } } else { match_slash = !flags.HasFlag(MatchFlags.PathName); } if (p.Value == '\0') { /* Trailing "**" matches everything. Trailing "*" matches * only if there are no more slash characters. */ if (!match_slash) { if (text.Source.Substring(text.Index).Contains("/")) { return(MatchResult.NoMatch); } } return((int)MatchResult.Match); } else if (!match_slash && p.Value == '/') { var nextIndex = text.Source.Substring(text.Index).IndexOf('/'); if (nextIndex == -1) { return(MatchResult.NoMatch); } text = text.Increment(nextIndex); break; } while (true) { if (t_ch == '\0') { break; } if (!Sane.IsGlobSpecial(p.Value)) { p_ch = p.Value; if ((flags.HasFlag(MatchFlags.CaseFold)) && char.IsUpper(p_ch)) { p_ch = char.ToLower(p_ch); } while ((t_ch = text.Value) != '\0' && (match_slash || t_ch != '/')) { if (flags.HasFlag(MatchFlags.CaseFold) && char.IsUpper(t_ch)) { t_ch = char.ToLower(t_ch); } if (t_ch == p_ch) { break; } text = text.Increment(); } if (t_ch != p_ch) { return(MatchResult.NoMatch); } } if ((matched = (int)DoWild(p, text, flags)) != (int)MatchResult.NoMatch) { if (!match_slash || matched != (int)MatchResult.AbortToStartStart) { return((MatchResult)matched); } } else if (!match_slash && t_ch == '/') { return(MatchResult.AbortToStartStart); } text = text.Increment(); t_ch = text.Value; } return(MatchResult.AbortAll); case '[': p = p.Increment(); p_ch = p.Value; if (p_ch == '^') { p_ch = '!'; } var negated = p_ch == '!' ? 1 : 0; if (negated == 1) { p = p.Increment(); p_ch = p.Value; } var prev_ch = '\0'; matched = 0; bool Next() { prev_ch = p_ch; p = p.Increment(); p_ch = p.Value; return(p_ch != ']'); } do { if (p_ch == '\0') { return(MatchResult.AbortAll); } if (p_ch == '\\') { p = p.Increment(); p_ch = p.Value; if (p_ch == '\0') { return(MatchResult.AbortAll); } if (t_ch == p_ch) { matched = 1; } } else if (p_ch == '-' && prev_ch != '\0' && p.Increment().Value != '\0' && p.Increment().Value != ']') { p = p.Increment(); p_ch = p.Value; if (p_ch == '\\') { p = p.Increment(); p_ch = p.Value; if (p_ch == '\0') { return(MatchResult.AbortAll); } } if (t_ch <= p_ch && t_ch >= prev_ch) { matched = 1; } else if (flags.HasFlag(MatchFlags.CaseFold) && char.IsLower(t_ch)) { var t_ch_upper = char.ToUpper(t_ch); if (t_ch_upper <= p_ch && t_ch_upper >= prev_ch) { matched = 1; } } p_ch = '\0'; } else if (p_ch == '[' && p.Increment().Value == ':') { CharPointer s; for (s = p.Increment(2); (p_ch = p.Value) != '\0' && p_ch != ']'; p = p.Increment()) { } if (p_ch == '\0') { return(MatchResult.AbortAll); } var i = p.Index - s.Index - 1; if (i < 0 || p.Increment(-1).Value != ':') { p = s.Increment(-2); p_ch = '['; if (t_ch == p_ch) { matched = 1; } continue; } var temp = s.Source.Substring(s.Index); if (temp.StartsWith("alnum")) { if (Sane.IsAlNum(t_ch)) { matched = 1; } } else if (temp.StartsWith("alpha")) { if (Sane.IsAlpha(t_ch)) { matched = 1; } } else if (temp.StartsWith("blank")) { if (Sane.IsBlank(t_ch)) { matched = 1; } } else if (temp.StartsWith("cntrl")) { if (Sane.IsCtrl(t_ch)) { matched = 1; } } else if (temp.StartsWith("digit")) { if (Sane.IsDigit(t_ch)) { matched = 1; } } else if (temp.StartsWith("graph")) { if (Sane.IsGraph(t_ch)) { matched = 1; } } else if (temp.StartsWith("lower")) { if (char.IsLower(t_ch)) { matched = 1; } } else if (temp.StartsWith("print")) { if (Sane.IsPrint(t_ch)) { matched = 1; } } else if (temp.StartsWith("punct")) { if (Sane.IsPunc(t_ch)) { matched = 1; } } else if (temp.StartsWith("space")) { if (Sane.IsSpace(t_ch)) { matched = 1; } } else if (temp.StartsWith("upper")) { if (char.IsUpper(t_ch)) { matched = 1; } else if (flags.HasFlag(MatchFlags.CaseFold) && char.IsLower(t_ch)) { matched = 1; } } else if (temp.StartsWith("xdigit")) { if (Sane.IsXDigit(t_ch)) { matched = 1; } } else { return(MatchResult.AbortAll); } } else if (t_ch == p_ch) { matched = 1; } } while (Next()); if (matched == negated || (flags.HasFlag(MatchFlags.PathName) && t_ch == '/')) { return(MatchResult.NoMatch); } continue; } } return(text.Index < text.Source.Length ? MatchResult.NoMatch : MatchResult.Match); }
/// <summary> /// Add multiple rules to the ignore list /// </summary> /// <param name="ignoreFilePath">Path to a text file containing a list of glob ignore patterns as strings</param> /// <param name="flags">Optional flags determining pattern matching behaviour</param> public void AddRules(string ignoreFilePath, MatchFlags flags = MatchFlags.PATHNAME) { AddRules(File.ReadAllLines(ignoreFilePath), flags, true); }
public ContentFilter(PropertyDefinition property, MatchOptions matchOptions, MatchFlags matchFlags) : base(property) { this.matchOptions = matchOptions; this.matchFlags = matchFlags; }
/// <summary> /// Add multiple rules to the ignore list /// </summary> /// <param name="ignoreFilePath">Path to a text file containing a list of glob ignore patterns as strings</param> /// <param name="flags">Optional flags determining pattern matching behaviour</param> public void AddRules(string ignoreFilePath, MatchFlags flags = MatchFlags.PATHNAME) { _rules.AddRange(CleanRules(File.ReadAllLines(ignoreFilePath)).Select(line => new IgnoreRule(line, flags))); }
/// <summary> /// Initializes a new instance of the <see cref="IgnoreRule"/> class. /// </summary> /// <param name="pattern">A glob pattern specifying file(s) this rule should ignore.</param> /// <param name="flags">Optional flags determining pattern matching behaviour.</param> /// <param name="lineNumber">Optional line number for logging purposes.</param> public IgnoreRule(string pattern, MatchFlags flags = MatchFlags.PATHNAME, int?lineNumber = null) { if (string.IsNullOrWhiteSpace(pattern)) { throw new ArgumentException("Pattern cannot be null or empty", nameof(pattern)); } LineNumber = lineNumber; // Keep track of the original pattern before modifications (for display purposes) OriginalPattern = pattern; Pattern = pattern; MatchFlags = flags; // First, let's figure out some things about the pattern and set flags to pass to our match function PatternFlags = PatternFlags.NONE; // If the pattern starts with an exclamation mark, it's a negation pattern // Once we know that, we can remove the exclamation mark (so the pattern behaves // just like any other), then just negate the match result when we return it if (Pattern.StartsWithCI("!")) { PatternFlags |= PatternFlags.NEGATION; Pattern = Pattern.Substring(1); } // If the pattern starts with a forward slash, it should only match an absolute path if (Pattern.StartsWithCI("/")) { PatternFlags |= PatternFlags.ABSOLUTE_PATH; Pattern = Pattern.Substring(1); } // If the pattern ends with a forward slash, it should only match a directory // Again though, once we know that we can remove the slash to normalise the pattern if (Pattern.EndsWithCI("/")) { PatternFlags |= PatternFlags.DIRECTORY; Pattern = Pattern.Substring(0, Pattern.Length - 1); } _wildcardIndex = Pattern.IndexOfAny(_wildcardChars); // If CASEFOLD is set, string comparisons should ignore case too if (MatchFlags.HasFlag(MatchFlags.CASEFOLD)) { _sc = StringComparison.OrdinalIgnoreCase; } // TODO: Currently, we are just setting PATHNAME for every rule // This is because it seems to match the original behaviour: // https://github.com/git/git/blob/c2c5f6b1e479f2c38e0e01345350620944e3527f/dir.c#L99 // If PATHNAME is set, single asterisks should not match slashes if (!MatchFlags.HasFlag(MatchFlags.PATHNAME)) { MatchFlags |= MatchFlags.PATHNAME; } var rxPattern = Matcher.ToRegex(Pattern); // If rxPattern is null, an invalid pattern was passed to ToRegex, so it cannot match if (!string.IsNullOrEmpty(rxPattern)) { var rxOptions = RegexOptions.Compiled; if (MatchFlags.HasFlag(MatchFlags.CASEFOLD)) { rxOptions |= RegexOptions.IgnoreCase; } _rx = new Regex(rxPattern, rxOptions); } }
public static int Match(object pattern, object data, out PhpArray matches, MatchFlags flags) { return Match(pattern, data, out matches, flags, 0, false); }
/// <summary> /// Add multiple rules to the ignore list /// </summary> /// <param name="rules">A list of glob ignore patterns as strings</param> /// <param name="flags">Optional flags determining pattern matching behaviour</param> public void AddRules(IEnumerable <string> rules, MatchFlags flags = MatchFlags.PATHNAME) { _rules.AddRange(CleanRules(rules).Select(line => new IgnoreRule(line, flags))); }
/// <summary> /// Private method implementing functions from match family. /// </summary> /// <param name="pattern">Perl regular expression match pattern.</param> /// <param name="data">String to search matches.</param> /// <param name="matches">An array containing matches found.</param> /// <param name="flags">Flags for searching.</param> /// <param name="offset">Offset to <paramref name="pattern"/> where the search should start.</param> /// <param name="matchAll"><B>True</B> if all matches should be found, <B>false</B> if only the first /// is enough.</param> /// <returns>Number of times the <paramref name="pattern"/> matches.</returns> private static int Match(object pattern, object data, out PhpArray matches, MatchFlags flags, int offset, bool matchAll) { // these two flags together do not make sense if ((flags & MatchFlags.PatternOrder) != 0 && (flags & MatchFlags.SetOrder) != 0) { PhpException.InvalidArgument("flags", LibResources.GetString("preg_match_pattern_set_order")); matches = null; return -1; } PerlRegExpConverter converter = ConvertPattern(pattern, null); if (converter == null) { matches = new PhpArray(); return -1; } string converted = ConvertData(data, converter); Match m = converter.Regex.Match(converted, offset>converted.Length?converted.Length:offset); if ((converter.PerlOptions & PerlRegexOptions.Anchored) > 0 && m.Success && m.Index != offset) { matches = new PhpArray(); return -1; } if (m.Success) { if (!matchAll || (flags & MatchFlags.PatternOrder) != 0) { matches = new PhpArray(m.Groups.Count); } else matches = new PhpArray(); if (!matchAll) { // Preg numbers groups sequentially, both named and unnamed. // .Net only numbers unnamed groups. // So we name unnamed groups (see ConvertRegex) to map correctly. int lastSuccessfulGroupIndex = GetLastSuccessfulGroup(m.Groups); var indexGroups = new List<Group>(m.Groups.Count); var groupNameByIndex = new Dictionary<int, string>(m.Groups.Count); for (int i = 0; i <= lastSuccessfulGroupIndex; i++) { // All groups should be named. var groupName = GetGroupName(converter.Regex, i); if (!string.IsNullOrEmpty(groupName)) { matches[groupName] = NewArrayItem(m.Groups[i].Value, m.Groups[i].Index, (flags & MatchFlags.OffsetCapture) != 0); } matches[i] = NewArrayItem(m.Groups[i].Value, m.Groups[i].Index, (flags & MatchFlags.OffsetCapture) != 0); } return 1; } // store all other matches in PhpArray matches if ((flags & MatchFlags.SetOrder) != 0) // cannot test PatternOrder, it is 0, SetOrder must be tested return FillMatchesArrayAllSetOrder(converter.Regex, m, ref matches, (flags & MatchFlags.OffsetCapture) != 0); else return FillMatchesArrayAllPatternOrder(converter.Regex, m, ref matches, (flags & MatchFlags.OffsetCapture) != 0); } // no match has been found if (matchAll && (flags & MatchFlags.SetOrder) == 0) { // in that case PHP returns an array filled with empty arrays according to parentheses count matches = new PhpArray(m.Groups.Count); for (int i = 0; i < converter.Regex.GetGroupNumbers().Length; i++) { AddGroupNameToResult(converter.Regex, matches, i, (ms,groupName) => { ms[groupName] = new PhpArray(0); }); matches[i] = new PhpArray(0); } } else { matches = new PhpArray(0); // empty array } return 0; }
public static MatchResult Match(string pattern, string text, MatchFlags matchFlags) { return(DoWild(pattern, text, matchFlags)); }