/* Match STRING against the filename pattern PATTERN, returning zero if
it matches, nonzero if not. */
-int
-fnmatch (pattern, string, flags)
- const char *pattern;
- const char *string;
- int flags;
+static int
+internal_function
+internal_fnmatch (const char *pattern, const char *string,
+ int no_leading_period, int flags)
{
register const char *p = pattern, *n = string;
register unsigned char c;
return FNM_NOMATCH;
else if (*n == '/' && (flags & FNM_FILE_NAME))
return FNM_NOMATCH;
- else if (*n == '.' && (flags & FNM_PERIOD) &&
- (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
+ else if (*n == '.' && no_leading_period)
return FNM_NOMATCH;
break;
break;
case '*':
- if (*n == '.' && (flags & FNM_PERIOD) &&
- (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
+ if (*n == '.' && no_leading_period)
return FNM_NOMATCH;
for (c = *p++; c == '?' || c == '*'; c = *p++)
if (c == '[')
{
for (--p; n < endp; ++n)
- if (fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
+ if (internal_fnmatch (p, n,
+ (n == string) && no_leading_period,
+ ((flags & FNM_FILE_NAME)
+ ? flags : (flags & ~FNM_PERIOD)))
+ == 0)
return 0;
}
+ else if (c == '/' && (flags & FNM_FILE_NAME))
+ {
+ while (*n != '\0' && *n != '/')
+ ++n;
+ if (*n == '/'
+ && (internal_fnmatch (p, n + 1, flags & FNM_PERIOD,
+ flags) == 0))
+ return 0;
+ }
else
{
if (c == '\\' && !(flags & FNM_NOESCAPE))
c = FOLD (c);
for (--p; n < endp; ++n)
if (FOLD ((unsigned char) *n) == c
- && fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
+ && (internal_fnmatch (p, n,
+ ((n == string)
+ && no_leading_period),
+ ((flags & FNM_FILE_NAME)
+ ? flags
+ : (flags & ~FNM_PERIOD)))
+ == 0))
return 0;
}
}
if (*n == '\0')
return FNM_NOMATCH;
- if (*n == '.' && (flags & FNM_PERIOD) &&
- (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
+ if (*n == '.' && no_leading_period)
return FNM_NOMATCH;
if (*n == '/' && (flags & FNM_FILE_NAME))
p += 2;
break;
}
- str[c1++] = 'c';
+ if (c < 'a' || c >= 'z')
+ {
+ /* This cannot possibly be a character class name.
+ Match it as a normal range. */
+ --p;
+ c = '[';
+ goto normal_bracket;
+ }
+ str[c1++] = c;
}
str[c1] = '\0';
else if (c == '\0')
/* [ (unterminated) loses. */
return FNM_NOMATCH;
- else if (FOLD (c) == fn)
- goto matched;
-
- cold = c;
- c = *p++;
-
- if (c == '-' && *p != ']')
+ else
{
- /* It is a range. */
- unsigned char cend = *p++;
- if (!(flags & FNM_NOESCAPE) && cend == '\\')
- cend = *p++;
- if (cend == '\0')
- return FNM_NOMATCH;
-
- if (cold <= fn && fn <= FOLD (cend))
+ normal_bracket:
+ if (FOLD (c) == fn)
goto matched;
+ cold = c;
c = *p++;
+
+ if (c == '-' && *p != ']')
+ {
+ /* It is a range. */
+ unsigned char cend = *p++;
+ if (!(flags & FNM_NOESCAPE) && cend == '\\')
+ cend = *p++;
+ if (cend == '\0')
+ return FNM_NOMATCH;
+
+ if (cold <= fn && fn <= FOLD (cend))
+ goto matched;
+
+ c = *p++;
+ }
}
+
if (c == ']')
break;
}
# undef FOLD
}
+
+int
+fnmatch (pattern, string, flags)
+ const char *pattern;
+ const char *string;
+ int flags;
+{
+ return internal_fnmatch (pattern, string, flags & FNM_PERIOD, flags);
+}
+
#endif /* _LIBC or not __GNU_LIBRARY__. */
{ "a/b", "[a-z]/[a-z]", 0, 0 },
{ "a/b", "*", FNM_FILE_NAME, FNM_NOMATCH },
{ "a/b", "*[/]b", FNM_FILE_NAME, FNM_NOMATCH },
- { "a/b", "*[b]", FNM_FILE_NAME, FNM_NOMATCH }
+ { "a/b", "*[b]", FNM_FILE_NAME, FNM_NOMATCH },
+ { "a/b", "[*]/b", 0, FNM_NOMATCH },
+ { "*/b", "[*]/b", 0, 0 },
+ { "a/b", "[?]/b", 0, FNM_NOMATCH },
+ { "?/b", "[?]/b", 0, 0 },
+ { "a/b", "[[a]/b", 0, 0 },
+ { "[/b", "[[a]/b", 0, 0 },
+ { "a/b", "\\*/b", 0, FNM_NOMATCH },
+ { "*/b", "\\*/b", 0, 0 },
+ { "a/b", "\\?/b", 0, FNM_NOMATCH },
+ { "?/b", "\\?/b", 0, 0 },
+ { "[/b", "[/b", 0, FNM_NOMATCH },
+ { "[/b", "\\[/b", 0, 0 },
+ { "aa/b", "??/b", 0, 0 },
+ { "aa/b", "???b", 0, 0 },
+ { "aa/b", "???b", FNM_PATHNAME, FNM_NOMATCH },
+ { ".a/b", "?a/b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
+ { "a/.b", "a/?b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
+ { ".a/b", "*a/b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
+ { "a/.b", "a/*b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
+ { ".a/b", "[.]a/b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
+ { "a/.b", "a/[.]b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
+ { "a/b", "*/?", FNM_PATHNAME|FNM_PERIOD, 0 },
+ { "a/b", "?/*", FNM_PATHNAME|FNM_PERIOD, 0 },
+ { ".a/b", ".*/?", FNM_PATHNAME|FNM_PERIOD, 0 },
+ { "a/.b", "*/.?", FNM_PATHNAME|FNM_PERIOD, 0 },
+ { "a/.b", "*/*", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
+ { "a/.b", "*?*/*", FNM_PERIOD, 0 },
+ { "a./b", "*[.]/b", FNM_PATHNAME|FNM_PERIOD, 0 },
+ { "a/b", "*[[:alpha:]]/*[[:alnum:]]", FNM_PATHNAME, 0 },
+ { "a/b", "*[![:digit:]]*/[![:d-d]", FNM_PATHNAME, 0 },
+ { "a/[", "*[![:digit:]]*/[![:d-d]", FNM_PATHNAME, FNM_NOMATCH },
};
int