xref: /csrg-svn/lib/libc/gen/fnmatch.c (revision 42624)
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * 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	5.2 (Berkeley) 06/01/90";
13 #endif /* LIBC_SCCS and not lint */
14 
15 /*
16  * Function fnmatch() as proposed in Posix 1003.2 B.6 (rev. 9).
17  * Compares a filename or pathname to a pattern.
18  */
19 
20 #include <unistd.h>
21 #include <string.h>
22 
23 #define	EOS	'\0'
24 
25 fnmatch(pattern, string, flags)
26 	register char *pattern, *string;
27 	int flags;
28 {
29 	register char c;
30 	char test, *rangematch();
31 
32 	for (;;)
33 		switch (c = *pattern++) {
34 		case EOS:
35 			return(*string == EOS);
36 		case '?':
37 			if ((test = *string++) == EOS ||
38 			    test == '/' && flags & FNM_PATHNAME)
39 				return(0);
40 			break;
41 		case '*':
42 			c = *pattern;
43 			/* collapse multiple stars */
44 			while (c == '*')
45 				c = *++pattern;
46 
47 			/* optimize for pattern with * at end or before / */
48 			if (c == EOS)
49 				if (flags & FNM_PATHNAME)
50 					return(!index(string, '/'));
51 				else
52 					return(1);
53 			else if (c == '/' && flags & FNM_PATHNAME) {
54 				if ((string = index(string, '/')) == NULL)
55 					return(0);
56 				break;
57 			}
58 
59 			/* general case, use recursion */
60 			while ((test = *string) != EOS) {
61 				if (fnmatch(pattern, string, flags))
62 					return(1);
63 				if (test == '/' && flags & FNM_PATHNAME)
64 					break;
65 				++string;
66 			}
67 			return(0);
68 		case '[':
69 			if ((test = *string++) == EOS ||
70 			    test == '/' && flags & FNM_PATHNAME)
71 				return(0);
72 			if ((pattern = rangematch(pattern, test)) == NULL)
73 				return(0);
74 			break;
75 		case '\\':
76 			if (flags & FNM_QUOTE) {
77 				if ((c = *pattern++) == EOS) {
78 					c = '\\';
79 					--pattern;
80 				}
81 				if (c != *string++)
82 					return(0);
83 				break;
84 			}
85 			/* FALLTHROUGH */
86 		default:
87 			if (c != *string++)
88 				return(0);
89 			break;
90 		}
91 }
92 
93 static char *
94 rangematch(pattern, test)
95 	register char *pattern, test;
96 {
97 	register char c, c2;
98 	int negate, ok;
99 
100 	if (negate = (*pattern == '!'))
101 		++pattern;
102 
103 	/*
104 	 * TO DO: quoting
105 	 */
106 
107 	for (ok = 0; (c = *pattern++) != ']';) {
108 		if (c == EOS)
109 			return(NULL);		/* illegal pattern */
110 		if (*pattern == '-' && (c2 = pattern[1]) != EOS && c2 != ']') {
111 			if (c <= test && test <= c2)
112 				ok = 1;
113 			pattern += 2;
114 		}
115 		else if (c == test)
116 			ok = 1;
117 	}
118 	return(ok == negate ? NULL : pattern);
119 }
120