xref: /original-bsd/lib/libc/gen/fnmatch.c (revision c3e32dec)
1 /*
2  * Copyright (c) 1989, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Guido van Rossum.
7  *
8  * %sccs.include.redist.c%
9  */
10 
11 #if defined(LIBC_SCCS) && !defined(lint)
12 static char sccsid[] = "@(#)fnmatch.c	8.1 (Berkeley) 06/04/93";
13 #endif /* LIBC_SCCS and not lint */
14 
15 /*
16  * Function fnmatch() as proposed in POSIX 1003.2 B.6 (D11.2).
17  * Compares a filename or pathname to a pattern.
18  */
19 
20 #include <fnmatch.h>
21 #include <string.h>
22 
23 #define	EOS	'\0'
24 
25 static const char *rangematch __P((const char *, int));
26 
27 fnmatch(pattern, string, flags)
28 	register const char *pattern, *string;
29 	int flags;
30 {
31 	register char c;
32 	char test;
33 
34 	for (;;)
35 		switch (c = *pattern++) {
36 		case EOS:
37 			return (*string == EOS ? 0 : FNM_NOMATCH);
38 		case '?':
39 			if ((test = *string++) == EOS ||
40 			    test == '/' && flags & FNM_PATHNAME)
41 				return (FNM_NOMATCH);
42 			break;
43 		case '*':
44 			c = *pattern;
45 			/* Collapse multiple stars. */
46 			while (c == '*')
47 				c = *++pattern;
48 
49 			/* Optimize for pattern with * at end or before /. */
50 			if (c == EOS)
51 				if (flags & FNM_PATHNAME)
52 					return (index(string, '/') == NULL ?
53 					    0 : FNM_NOMATCH);
54 				else
55 					return (0);
56 			else if (c == '/' && flags & FNM_PATHNAME) {
57 				if ((string = index(string, '/')) == NULL)
58 					return (FNM_NOMATCH);
59 				break;
60 			}
61 
62 			/* General case, use recursion. */
63 			while ((test = *string) != EOS) {
64 				if (!fnmatch(pattern, string, flags))
65 					return (0);
66 				if (test == '/' && flags & FNM_PATHNAME)
67 					break;
68 				++string;
69 			}
70 			return (FNM_NOMATCH);
71 		case '[':
72 			if ((test = *string++) == EOS ||
73 			    test == '/' && flags & FNM_PATHNAME)
74 				return (FNM_NOMATCH);
75 			if ((pattern = rangematch(pattern, test)) == NULL)
76 				return (FNM_NOMATCH);
77 			break;
78 		case '\\':
79 			if (!(flags & FNM_NOESCAPE)) {
80 				if ((c = *pattern++) == EOS) {
81 					c = '\\';
82 					--pattern;
83 				}
84 				if (c != *string++)
85 					return (FNM_NOMATCH);
86 				break;
87 			}
88 			/* FALLTHROUGH */
89 		default:
90 			if (c != *string++)
91 				return (FNM_NOMATCH);
92 			break;
93 		}
94 	/* NOTREACHED */
95 }
96 
97 static const char *
98 rangematch(pattern, test)
99 	register const char *pattern;
100 	register int test;
101 {
102 	register char c, c2;
103 	int negate, ok;
104 
105 	if (negate = (*pattern == '!'))
106 		++pattern;
107 
108 	/*
109 	 * XXX
110 	 * TO DO: quoting
111 	 */
112 	for (ok = 0; (c = *pattern++) != ']';) {
113 		if (c == EOS)
114 			return (NULL);		/* Illegal pattern. */
115 		if (*pattern == '-' && (c2 = pattern[1]) != EOS && c2 != ']') {
116 			if (c <= test && test <= c2)
117 				ok = 1;
118 			pattern += 2;
119 		}
120 		else if (c == test)
121 			ok = 1;
122 	}
123 	return (ok == negate ? NULL : pattern);
124 }
125