summaryrefslogtreecommitdiff
path: root/lib/glob/fnmatch.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/glob/fnmatch.c')
-rw-r--r--lib/glob/fnmatch.c75
1 files changed, 60 insertions, 15 deletions
diff --git a/lib/glob/fnmatch.c b/lib/glob/fnmatch.c
index 07636090..2f8eb240 100644
--- a/lib/glob/fnmatch.c
+++ b/lib/glob/fnmatch.c
@@ -50,15 +50,23 @@ fnmatch (pattern, string, flags)
if (*n == '\0')
return (FNM_NOMATCH);
else if ((flags & FNM_PATHNAME) && *n == '/')
+ /* If we are matching a pathname, `?' can never match a `/'. */
return (FNM_NOMATCH);
else if ((flags & FNM_PERIOD) && *n == '.' &&
(n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
+ /* `?' cannot match a `.' if it is the first character of the
+ string or if it is the first character following a slash and
+ we are matching a pathname. */
return (FNM_NOMATCH);
break;
case '\\':
if (!(flags & FNM_NOESCAPE))
- c = *p++;
+ {
+ c = *p++;
+ if (c == '\0')
+ return (FNM_NOMATCH);
+ }
if (*n != c)
return (FNM_NOMATCH);
break;
@@ -66,23 +74,38 @@ fnmatch (pattern, string, flags)
case '*':
if ((flags & FNM_PERIOD) && *n == '.' &&
(n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
+ /* `*' cannot match a `.' if it is the first character of the
+ string or if it is the first character following a slash and
+ we are matching a pathname. */
return (FNM_NOMATCH);
+ /* Collapse multiple consecutive, `*' and `?', but make sure that
+ one character of the string is consumed for each `?'. */
for (c = *p++; c == '?' || c == '*'; c = *p++)
{
- if (((flags & FNM_PATHNAME) && *n == '/') ||
- (c == '?' && *n == '\0'))
+ if ((flags & FNM_PATHNAME) && *n == '/')
+ /* A slash does not match a wildcard under FNM_PATHNAME. */
return (FNM_NOMATCH);
- if (c == '?')
- n++;
+ else if (c == '?')
+ {
+ if (*n == '\0')
+ return (FNM_NOMATCH);
+ /* One character of the string is consumed in matching
+ this ? wildcard, so *??? won't match if there are
+ fewer than three characters. */
+ n++;
+ }
}
if (c == '\0')
return (0);
+ /* General case, use recursion. */
{
char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
for (--p; *n != '\0'; ++n)
+ /* Only call fnmatch if the first character indicates a
+ possible match. */
if ((c == '[' || *n == c1) &&
fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
return (0);
@@ -97,22 +120,30 @@ fnmatch (pattern, string, flags)
if (*n == '\0')
return (FNM_NOMATCH);
+ /* A character class cannot match a `.' if it is the first
+ character of the string or if it is the first character
+ following a slash and we are matching a pathname. */
if ((flags & FNM_PERIOD) && *n == '.' &&
(n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
return (FNM_NOMATCH);
- /* Make sure there is a closing `]'. If there isn't, the `['
- is just a character to be matched. */
+ /* POSIX.2 2.8.3.1.2 says: `An expression containing a `[' that
+ is not preceded by a backslash and is not part of a bracket
+ expression produces undefined results.' This implementation
+ treats the `[' as just a character to be matched if there is
+ not a closing `]'. This code will have to be changed when
+ POSIX.2 character classes are implemented. */
{
register char *np;
- for (np = p; np && *np && *np != ']'; np++);
+ for (np = p; np && *np && *np != ']'; np++)
+ ;
if (np && !*np)
{
if (*n != '[')
return (FNM_NOMATCH);
- goto next_char;
+ break;
}
}
@@ -123,10 +154,18 @@ fnmatch (pattern, string, flags)
c = *p++;
for (;;)
{
- register char cstart = c, cend = c;
+ register char cstart, cend;
+
+ /* Initialize cstart and cend in case `-' is the last
+ character of the pattern. */
+ cstart = cend = c;
if (!(flags & FNM_NOESCAPE) && c == '\\')
- cstart = cend = *p++;
+ {
+ if (*p == '\0')
+ return FNM_NOMATCH;
+ cstart = cend = *p++;
+ }
if (c == '\0')
/* [ (unterminated) loses. */
@@ -138,6 +177,9 @@ fnmatch (pattern, string, flags)
/* [/] can never match. */
return (FNM_NOMATCH);
+ /* This introduces a range, unless the `-' is the last
+ character of the class. Find the end of the range
+ and move past it. */
if (c == '-' && *p != ']')
{
cend = *p++;
@@ -145,6 +187,7 @@ fnmatch (pattern, string, flags)
cend = *p++;
if (cend == '\0')
return (FNM_NOMATCH);
+
c = *p++;
}
@@ -156,8 +199,6 @@ fnmatch (pattern, string, flags)
}
if (!not)
return (FNM_NOMATCH);
-
- next_char:
break;
matched:
@@ -170,8 +211,12 @@ fnmatch (pattern, string, flags)
c = *p++;
if (!(flags & FNM_NOESCAPE) && c == '\\')
- /* 1003.2d11 is unclear if this is right. %%% */
- ++p;
+ {
+ if (*p == '\0')
+ return FNM_NOMATCH;
+ /* XXX 1003.2d11 is unclear if this is right. */
+ ++p;
+ }
}
if (not)
return (FNM_NOMATCH);