@@ -45,32 +45,46 @@ bool PathMatch::match(const std::string &pattern, const std::string &path, const
4545 if (pattern == " *" || pattern == " **" )
4646 return true ;
4747
48+ /* A "real" path is absolute or relative to the base path. A pattern that isn't "real" can match at any
49+ * path component boundary. */
4850 bool real = Path::isAbsolute (pattern) || pattern[0 ] == ' .' ;
4951
52+ /* Pattern iterator */
5053 PathIterator s = PathIterator::from_pattern (pattern, basepath, mode == Mode::icase);
54+ /* Path iterator */
5155 PathIterator t = PathIterator::from_path (path, basepath, mode == Mode::icase);
56+ /* Pattern restart position */
5257 PathIterator p = s;
58+ /* Path restart position */
5359 PathIterator q = t;
5460
61+ /* Backtrack stack */
5562 std::stack<std::pair<PathIterator::Pos, PathIterator::Pos>> b;
5663
5764 for (;;) {
5865 switch (*s) {
66+ /* Star or star-star, matches any number of characters */
5967 case ' *' : {
6068 bool slash = false ;
6169 ++s;
6270 if (*s == ' *' ) {
71+ /* Star-star matches slashes as well */
6372 slash = true ;
6473 ++s;
6574 }
75+ /* Add backtrack for matching zero characters */
6676 b.emplace (s.getpos (), t.getpos ());
6777 while (*t != ' \0 ' && (slash || *t != ' /' )) {
68- if (*s == *t)
78+ if (*s == *t) {
79+ /* Could stop here, but do greedy match and add
80+ * backtrack instead */
6981 b.emplace (s.getpos (), t.getpos ());
82+ }
7083 ++t;
7184 }
7285 continue ;
7386 }
87+ /* Single character wildcard */
7488 case ' ?' : {
7589 if (*t != ' \0 ' && *t != ' /' ) {
7690 ++s;
@@ -79,11 +93,14 @@ bool PathMatch::match(const std::string &pattern, const std::string &path, const
7993 }
8094 break ;
8195 }
96+ /* Start of pattern; matches start of path, or a path separator if the
97+ * pattern is not "real" (an absolute or relative path). */
8298 case ' \0 ' : {
8399 if (*t == ' \0 ' || (*t == ' /' && !real))
84100 return true ;
85101 break ;
86102 }
103+ /* Literal character */
87104 default : {
88105 if (*s == *t) {
89106 ++s;
@@ -94,6 +111,7 @@ bool PathMatch::match(const std::string &pattern, const std::string &path, const
94111 }
95112 }
96113
114+ /* No match, try to backtrack */
97115 if (!b.empty ()) {
98116 const auto &bp = b.top ();
99117 b.pop ();
@@ -102,6 +120,7 @@ bool PathMatch::match(const std::string &pattern, const std::string &path, const
102120 continue ;
103121 }
104122
123+ /* Couldn't bactrack, try matching from the next path separator */
105124 while (*q != ' \0 ' && *q != ' /' )
106125 ++q;
107126
@@ -112,6 +131,7 @@ bool PathMatch::match(const std::string &pattern, const std::string &path, const
112131 continue ;
113132 }
114133
134+ /* No more path seperators to try from */
115135 return false ;
116136 }
117137}
0 commit comments