master
go 98 lines 2.18 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package matcher
4
5 import (
6 "errors"
7 "fmt"
8 "strings"
9 )
10
11 type (
12 simplePatternTerm struct {
13 matcher Matcher
14 positive bool
15 }
16
17 // simplePatternsMatcher patterns.
18 simplePatternsMatcher []simplePatternTerm
19 )
20
21 // NewSimplePatternsMatcher creates new simple patterns. It returns error in case one of patterns has bad syntax.
22 func NewSimplePatternsMatcher(expr string) (Matcher, error) {
23 ps := simplePatternsMatcher{}
24
25 for pattern := range strings.FieldsSeq(expr) {
26 positive := true
27 if strings.HasPrefix(pattern, "!") {
28 positive = false
29 pattern = strings.TrimPrefix(pattern, "!")
30 }
31 if err := ps.add(pattern, positive); err != nil {
32 return nil, err
33 }
34 }
35 if len(ps) == 0 {
36 return FALSE(), nil
37 }
38 return ps, nil
39 }
40
41 // NewSimplePatternListMatcher creates a simple-patterns matcher from a pre-split
42 // list of glob patterns. Use it when individual patterns may contain whitespace.
43 func NewSimplePatternListMatcher(patterns []string) (Matcher, error) {
44 ps := simplePatternsMatcher{}
45 hasPositive := false
46
47 for _, pattern := range patterns {
48 pattern = strings.TrimSpace(pattern)
49 if pattern == "" {
50 continue
51 }
52 negative := strings.HasPrefix(pattern, "!")
53 if negative {
54 pattern = strings.TrimSpace(strings.TrimPrefix(pattern, "!"))
55 }
56 if pattern == "" {
57 return nil, errors.New("invalid empty negative pattern")
58 }
59 hasPositive = hasPositive || !negative
60 if err := ps.add(pattern, !negative); err != nil {
61 return nil, fmt.Errorf("invalid pattern: %w", err)
62 }
63 }
64 if len(ps) == 0 {
65 return FALSE(), nil
66 }
67 if !hasPositive {
68 return nil, errors.New("must include at least one positive pattern")
69 }
70 return ps, nil
71 }
72
73 func (m *simplePatternsMatcher) add(term string, positive bool) error {
74 p := simplePatternTerm{positive: positive}
75 matcher, err := NewGlobMatcher(term)
76 if err != nil {
77 return err
78 }
79
80 p.matcher = matcher
81 *m = append(*m, p)
82
83 return nil
84 }
85
86 func (m simplePatternsMatcher) Match(b []byte) bool {
87 return m.MatchString(string(b))
88 }
89
90 // MatchString matches.
91 func (m simplePatternsMatcher) MatchString(line string) bool {
92 for _, p := range m {
93 if p.matcher.MatchString(line) {
94 return p.positive
95 }
96 }
97 return false
98 }