summaryrefslogtreecommitdiff
path: root/posix/fnmatch.c
diff options
context:
space:
mode:
Diffstat (limited to 'posix/fnmatch.c')
-rw-r--r--posix/fnmatch.c96
1 files changed, 67 insertions, 29 deletions
diff --git a/posix/fnmatch.c b/posix/fnmatch.c
index e0ff2c34d2..d31c375bd2 100644
--- a/posix/fnmatch.c
+++ b/posix/fnmatch.c
@@ -129,11 +129,10 @@ extern int errno;
/* 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;
@@ -156,8 +155,7 @@ fnmatch (pattern, string, flags)
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;
@@ -175,8 +173,7 @@ fnmatch (pattern, string, flags)
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++)
@@ -214,9 +211,22 @@ fnmatch (pattern, string, flags)
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))
@@ -224,7 +234,13 @@ fnmatch (pattern, string, flags)
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;
}
}
@@ -245,8 +261,7 @@ fnmatch (pattern, string, flags)
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))
@@ -294,7 +309,15 @@ fnmatch (pattern, string, flags)
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';
@@ -325,26 +348,31 @@ fnmatch (pattern, string, flags)
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;
}
@@ -404,4 +432,14 @@ fnmatch (pattern, string, flags)
# 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__. */