summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/fnmatch.h7
-rw-r--r--lib/libc/gen/fnmatch.326
-rw-r--r--lib/libc/gen/fnmatch.c88
3 files changed, 98 insertions, 23 deletions
diff --git a/include/fnmatch.h b/include/fnmatch.h
index 62f483f7223..38cf14fd34c 100644
--- a/include/fnmatch.h
+++ b/include/fnmatch.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: fnmatch.h,v 1.2 1997/09/21 10:45:33 niklas Exp $ */
+/* $OpenBSD: fnmatch.h,v 1.3 1997/09/22 05:03:30 millert Exp $ */
/* $NetBSD: fnmatch.h,v 1.5 1994/10/26 00:55:53 cgd Exp $ */
/*-
@@ -44,6 +44,11 @@
#define FNM_NOESCAPE 0x01 /* Disable backslash escaping. */
#define FNM_PATHNAME 0x02 /* Slash must be matched by slash. */
#define FNM_PERIOD 0x04 /* Period must be matched by period. */
+#ifndef _POSIX_SOURCE
+#define FNM_LEADING_DIR 0x08 /* Ignore /<tail> after Imatch. */
+#define FNM_CASEFOLD 0x10 /* Case insensitive search. */
+#define FNM_IGNORECASE FNM_CASEFOLD
+#endif
#include <sys/cdefs.h>
diff --git a/lib/libc/gen/fnmatch.3 b/lib/libc/gen/fnmatch.3
index 951ed647d33..824ef43974e 100644
--- a/lib/libc/gen/fnmatch.3
+++ b/lib/libc/gen/fnmatch.3
@@ -1,4 +1,4 @@
-.\" $OpenBSD: fnmatch.3,v 1.3 1997/06/13 13:01:44 deraadt Exp $
+.\" $OpenBSD: fnmatch.3,v 1.4 1997/09/22 05:03:29 millert Exp $
.\"
.\" Copyright (c) 1989, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
@@ -33,7 +33,9 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd April 16, 1994
+.\" @(#)fnmatch.3 8.3 (Berkeley) 4/28/95
+.\"
+.Dd April 28, 1995
.Dt FNMATCH 3
.Os
.Sh NAME
@@ -85,7 +87,12 @@ must be explicitly matched by slashes in
.Fa pattern .
If this flag is not set, then slashes are treated as regular characters.
.It Dv FNM_PERIOD
-Leading periods in strings match periods in patterns.
+Leading periods in
+.Fa string
+must be explicitly matched by periods in
+.Fa pattern .
+If this flag is not set, then leading periods are treated as regular
+characters.
The definition of ``leading'' is related to the specification of
.Dv FNM_PATHNAME.
A period is always ``leading'' if it is the first character in
@@ -94,6 +101,17 @@ Additionally, if
.Dv FNM_PATHNAME
is set,
a period is ``leading'' if it immediately follows a slash.
+.It Dv FNM_LEADING_DIR
+Ignore
+.Nm /*
+rest after successful
+.Fa pattern
+matching.
+.It Dv FNM_CASEFOLD
+Ignore case distinctions in both the
+.Fa pattern
+and the
+.Fa string .
.El
.Sh RETURN VALUES
The
@@ -116,7 +134,7 @@ function conforms to
.Sh HISTORY
The
.Fn fnmatch
-function first appeared in
+function first appeared in
.Bx 4.4 .
.Sh BUGS
The pattern
diff --git a/lib/libc/gen/fnmatch.c b/lib/libc/gen/fnmatch.c
index d2b6e5eb8c5..5063ff36a44 100644
--- a/lib/libc/gen/fnmatch.c
+++ b/lib/libc/gen/fnmatch.c
@@ -1,3 +1,5 @@
+/* $OpenBSD: fnmatch.c,v 1.5 1997/09/22 05:03:30 millert Exp $ */
+
/*
* Copyright (c) 1989, 1993, 1994
* The Regents of the University of California. All rights reserved.
@@ -35,7 +37,11 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static char rcsid[] = "$OpenBSD: fnmatch.c,v 1.4 1997/07/23 21:09:04 kstailey Exp $";
+#if 0
+static char sccsid[] = "@(#)fnmatch.c 8.2 (Berkeley) 4/16/94";
+#else
+static char rcsid[] = "$OpenBSD: fnmatch.c,v 1.5 1997/09/22 05:03:30 millert Exp $";
+#endif
#endif /* LIBC_SCCS and not lint */
/*
@@ -43,12 +49,18 @@ static char rcsid[] = "$OpenBSD: fnmatch.c,v 1.4 1997/07/23 21:09:04 kstailey Ex
* Compares a filename or pathname to a pattern.
*/
-#include <fnmatch.h>
+#include <ctype.h>
+#include <stdio.h>
#include <string.h>
+#include <fnmatch.h>
#define EOS '\0'
-static const char *rangematch __P((const char *, int, int));
+#define RANGE_MATCH 1
+#define RANGE_NOMATCH 0
+#define RANGE_ERROR (-1)
+
+static int rangematch __P((const char *, char, int, char **));
int
fnmatch(pattern, string, flags)
@@ -56,11 +68,14 @@ fnmatch(pattern, string, flags)
int flags;
{
const char *stringstart;
+ char *newp;
char c, test;
for (stringstart = string;;)
switch (c = *pattern++) {
case EOS:
+ if ((flags & FNM_LEADING_DIR) && *string == '/')
+ return (0);
return (*string == EOS ? 0 : FNM_NOMATCH);
case '?':
if (*string == EOS)
@@ -87,11 +102,12 @@ fnmatch(pattern, string, flags)
/* Optimize for pattern with * at end or before /. */
if (c == EOS)
if (flags & FNM_PATHNAME)
- return (strchr(string, '/') == NULL ?
+ return ((flags & FNM_LEADING_DIR) ||
+ strchr(string, '/') == NULL ?
0 : FNM_NOMATCH);
else
return (0);
- else if (c == '/' && flags & FNM_PATHNAME) {
+ else if (c == '/' && (flags & FNM_PATHNAME)) {
if ((string = strchr(string, '/')) == NULL)
return (FNM_NOMATCH);
break;
@@ -101,7 +117,7 @@ fnmatch(pattern, string, flags)
while ((test = *string) != EOS) {
if (!fnmatch(pattern, string, flags & ~FNM_PERIOD))
return (0);
- if (test == '/' && flags & FNM_PATHNAME)
+ if (test == '/' && (flags & FNM_PATHNAME))
break;
++string;
}
@@ -109,11 +125,23 @@ fnmatch(pattern, string, flags)
case '[':
if (*string == EOS)
return (FNM_NOMATCH);
- if (*string == '/' && flags & FNM_PATHNAME)
+ if (*string == '/' && (flags & FNM_PATHNAME))
+ return (FNM_NOMATCH);
+ if (*string == '.' && (flags & FNM_PERIOD) &&
+ (string == stringstart ||
+ ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
return (FNM_NOMATCH);
- if ((pattern =
- rangematch(pattern, *string, flags)) == NULL)
+
+ switch (rangematch(pattern, *string, flags, &newp)) {
+ case RANGE_ERROR:
+ /* not a good range, treat as normal text */
+ goto normal;
+ case RANGE_MATCH:
+ pattern = newp;
+ break;
+ case RANGE_NOMATCH:
return (FNM_NOMATCH);
+ }
++string;
break;
case '\\':
@@ -125,17 +153,23 @@ fnmatch(pattern, string, flags)
}
/* FALLTHROUGH */
default:
- if (c != *string++)
+ normal:
+ if (c != *string && !((flags & FNM_CASEFOLD) &&
+ (tolower((unsigned char)c) ==
+ tolower((unsigned char)*string))))
return (FNM_NOMATCH);
+ ++string;
break;
}
/* NOTREACHED */
}
-static const char *
-rangematch(pattern, test, flags)
+static int
+rangematch(pattern, test, flags, newp)
const char *pattern;
- int test, flags;
+ char test;
+ int flags;
+ char **newp;
{
int negate, ok;
char c, c2;
@@ -150,22 +184,40 @@ rangematch(pattern, test, flags)
if ((negate = (*pattern == '!' || *pattern == '^')))
++pattern;
- for (ok = 0; (c = *pattern++) != ']';) {
+ if (flags & FNM_CASEFOLD)
+ test = tolower((unsigned char)test);
+
+ /*
+ * A right bracket shall lose its special meaning and represent
+ * itself in a bracket expression if it occurs first in the list.
+ * -- POSIX.2 2.8.3.2
+ */
+ ok = 0;
+ c = *pattern++;
+ do {
if (c == '\\' && !(flags & FNM_NOESCAPE))
c = *pattern++;
if (c == EOS)
- return (NULL);
+ return (RANGE_ERROR);
+ if (c == '/' && (flags & FNM_PATHNAME))
+ return (RANGE_NOMATCH);
+ if ((flags & FNM_CASEFOLD))
+ c = tolower((unsigned char)c);
if (*pattern == '-'
&& (c2 = *(pattern+1)) != EOS && c2 != ']') {
pattern += 2;
if (c2 == '\\' && !(flags & FNM_NOESCAPE))
c2 = *pattern++;
if (c2 == EOS)
- return (NULL);
+ return (RANGE_ERROR);
+ if (flags & FNM_CASEFOLD)
+ c2 = tolower((unsigned char)c2);
if (c <= test && test <= c2)
ok = 1;
} else if (c == test)
ok = 1;
- }
- return (ok == negate ? NULL : pattern);
+ } while ((c = *pattern++) != ']');
+
+ *newp = (char *)pattern;
+ return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH);
}