forked from Tracktion/choc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
choc_Wildcard.h
130 lines (102 loc) · 4.61 KB
/
choc_Wildcard.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//
// ██████ ██ ██ ██████ ██████
// ██ ██ ██ ██ ██ ██ ** Classy Header-Only Classes **
// ██ ███████ ██ ██ ██
// ██ ██ ██ ██ ██ ██ https://github.com/Tracktion/choc
// ██████ ██ ██ ██████ ██████
//
// CHOC is (C)2022 Tracktion Corporation, and is offered under the terms of the ISC license:
//
// Permission to use, copy, modify, and/or distribute this software for any purpose with or
// without fee is hereby granted, provided that the above copyright notice and this permission
// notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
// CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#ifndef CHOC_WILDCARD_HEADER_INCLUDED
#define CHOC_WILDCARD_HEADER_INCLUDED
#include "../text/choc_UTF8.h"
namespace choc::text
{
//==============================================================================
/**
A wildcard pattern-matcher for filename-style patterns.
This handles the kind of simple wildcards that you'd give to a filesystem search.
It recognises:
- '*' = any sequence of zero or more characters
- '?' = any character
It accepts a string containing multiple patterns separated by semi-colons, and
considers it a successful match if any of these match.
E.g. "*.foo;*.blah" will match strings that end either either ".foo" or ".blah".
*/
struct WildcardPattern
{
WildcardPattern() = default;
WildcardPattern (WildcardPattern&&) = default;
WildcardPattern& operator= (WildcardPattern&&) = default;
/// Creates a matcher for the given pattern.
WildcardPattern (std::string_view pattern, bool caseSensitive);
/// Returns true if the given string matches the pattern.
bool matches (const std::string& text) const;
private:
std::vector<std::string> patterns;
bool isCaseSensitive;
bool matchesAnywhere (choc::text::UTF8Pointer, choc::text::UTF8Pointer) const;
bool matchesAll (choc::text::UTF8Pointer, choc::text::UTF8Pointer) const;
};
//==============================================================================
// _ _ _ _
// __| | ___ | |_ __ _ (_)| | ___
// / _` | / _ \| __| / _` || || |/ __|
// | (_| || __/| |_ | (_| || || |\__ \ _ _ _
// \__,_| \___| \__| \__,_||_||_||___/(_)(_)(_)
//
// Code beyond this point is implementation detail...
//
//==============================================================================
inline WildcardPattern::WildcardPattern (std::string_view pattern, bool caseSensitive)
: isCaseSensitive (caseSensitive)
{
for (auto& p : choc::text::splitString (pattern, ';', false))
patterns.push_back (choc::text::trim (p));
}
inline bool WildcardPattern::matches (const std::string& text) const
{
if (patterns.empty())
return true;
choc::text::UTF8Pointer t (text.c_str());
for (auto& p : patterns)
if (matchesAll (t, choc::text::UTF8Pointer (p.c_str())))
return true;
return false;
}
inline bool WildcardPattern::matchesAnywhere (choc::text::UTF8Pointer source, choc::text::UTF8Pointer pattern) const
{
while (! source.empty())
{
if (matchesAll (source, pattern))
return true;
++source;
}
return false;
}
inline bool WildcardPattern::matchesAll (choc::text::UTF8Pointer source, choc::text::UTF8Pointer pattern) const
{
for (;;)
{
auto patternChar = pattern.popFirstChar();
if (patternChar == '*')
return pattern.empty() || matchesAnywhere (source, pattern);
auto sourceChar = source.popFirstChar();
if (! (sourceChar == patternChar
|| (! isCaseSensitive && std::towupper (static_cast<std::wint_t> (sourceChar)) == std::towupper (static_cast<std::wint_t> (patternChar)))
|| (patternChar == '?' && sourceChar != 0)))
return false;
if (patternChar == 0)
return true;
}
}
} // namespace choc::text
#endif // CHOC_WILDCARD_HEADER_INCLUDED