Implement documented wildcard escaping in wnmatch_sub

This commit is contained in:
Andrea Mazzoleni 2026-08-26 12:43:17 +02:00
parent 3bd3eff451
commit 35977dadc9
3 changed files with 45 additions and 0 deletions

View file

@ -863,6 +863,24 @@ struct {
{ "Movies*", "Movies4", 0, 0 },
{ "Movies*", "Movies4/file.mkv", 0, 1 },
/* escaping of wildcard metacharacters */
{ "foo\\*bar", "foo*bar", 0, 0 },
{ "foo\\?bar", "foo?bar", 0, 0 },
{ "foo\\[bar", "foo[bar", 0, 0 },
{ "foo\\]bar", "foo]bar", 0, 0 },
{ "foo\\\\bar", "foo\\bar", 0, 0 },
{ "foo\\*bar", "fooXXXbar", 0, 1 },
{ "foo\\?bar", "fooXbar", 0, 1 },
{ "foo\\[bar", "fooXbar", 0, 1 },
{ "foo\\]bar", "fooXbar", 0, 1 },
{ "foo*bar", "fooXXXbar", 0, 0 },
{ "foo?bar", "fooXbar", 0, 0 },
{ "foo[abc]bar", "fooabar", 0, 0 },
{ "foo\\abar", "foo\\abar", 0, 0 },
{ "foo\\abar", "fooabar", 0, 1 },
{ "foo\\", "foo\\", 0, 0 },
{ "foo\\", "foo", 0, 1 },
{ 0 }
};

View file

@ -360,12 +360,38 @@ static inline int wnmatch_end(const char* t, int match_sub)
}
}
static inline int is_wild_escape(char c)
{
return c == '*'
|| c == '?'
|| c == '['
|| c == ']'
|| c == '\\';
}
int wnmatch_sub(const char* p, const char* t, int match_sub)
{
char p1 = 0; /* previous char */
while (*p) {
char p0 = *p;
switch (p0) {
case '\\' :
/*
* Escape wildcard metacharacters.
*
* '\' is the canonical internal escape character.
* On Windows, pathimport() converts the external '^'
* escape syntax to this form before matching.
*/
if (is_wild_escape(p[1]))
++p;
if (*t == 0 || !char_match(*p, *t))
return 1;
++p;
++t;
break;
case '?' :
/* ? matches any single character except / */
if (*t == 0 || *t == '/')

View file

@ -127,6 +127,7 @@ unsigned strtou(const char* nptr, char** endptr, int base);
* - ** (not near a /) like *
* - ##/ reduces to nothing in addition to the normal matching of ** (using # instead of * to not mess the C comment)
* - [...] matches character classes with support for ranges and negation lile [!...] or [^...], except /
* - \ escapes *, ?, [, ], and \
*
* \return 0 if it matches
*/