xref: /original-bsd/lib/libc/gen/fnmatch.c (revision 04218a6a)
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  * Redistribution and use in source and binary forms are permitted
9  * provided that the above copyright notice and this paragraph are
10  * duplicated in all such forms and that any documentation,
11  * advertising materials, and other materials related to such
12  * distribution and use acknowledge that the software was developed
13  * by the University of California, Berkeley.  The name of the
14  * University may not be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19  */
20 
21 #if defined(LIBC_SCCS) && !defined(lint)
22 static char sccsid[] = "@(#)fnmatch.c	5.1 (Berkeley) 12/19/89";
23 #endif /* LIBC_SCCS and not lint */
24 
25 /*
26  * Function fnmatch() as proposed in Posix 1003.2 B.6 (rev. 9).
27  * Compares a filename or pathname to a pattern.
28  */
29 
30 #include <unistd.h>
31 #include <string.h>
32 
33 #define	EOS	'\0'
34 
35 fnmatch(pattern, string, flags)
36 	register char *pattern, *string;
37 	int flags;
38 {
39 	register char c;
40 	char test, *rangematch();
41 
42 	for (;;)
43 		switch (c = *pattern++) {
44 		case EOS:
45 			return(*string == EOS);
46 		case '?':
47 			if ((test = *string++) == EOS ||
48 			    test == '/' && flags & FNM_PATHNAME)
49 				return(0);
50 			break;
51 		case '*':
52 			c = *pattern;
53 			/* collapse multiple stars */
54 			while (c == '*')
55 				c = *++pattern;
56 
57 			/* optimize for pattern with * at end or before / */
58 			if (c == EOS)
59 				if (flags & FNM_PATHNAME)
60 					return(!index(string, '/'));
61 				else
62 					return(1);
63 			else if (c == '/' && flags & FNM_PATHNAME) {
64 				if ((string = index(string, '/')) == NULL)
65 					return(0);
66 				break;
67 			}
68 
69 			/* general case, use recursion */
70 			while ((test = *string) != EOS) {
71 				if (fnmatch(pattern, string, flags))
72 					return(1);
73 				if (test == '/' && flags & FNM_PATHNAME)
74 					break;
75 				++string;
76 			}
77 			return(0);
78 		case '[':
79 			if ((test = *string++) == EOS ||
80 			    test == '/' && flags & FNM_PATHNAME)
81 				return(0);
82 			if ((pattern = rangematch(pattern, test)) == NULL)
83 				return(0);
84 			break;
85 		case '\\':
86 			if (flags & FNM_QUOTE) {
87 				if ((c = *pattern++) == EOS) {
88 					c = '\\';
89 					--pattern;
90 				}
91 				if (c != *string++)
92 					return(0);
93 				break;
94 			}
95 			/* FALLTHROUGH */
96 		default:
97 			if (c != *string++)
98 				return(0);
99 			break;
100 		}
101 }
102 
103 static char *
104 rangematch(pattern, test)
105 	register char *pattern, test;
106 {
107 	register char c, c2;
108 	int negate, ok;
109 
110 	if (negate = (*pattern == '!'))
111 		++pattern;
112 
113 	/*
114 	 * TO DO: quoting
115 	 */
116 
117 	for (ok = 0; (c = *pattern++) != ']';) {
118 		if (c == EOS)
119 			return(NULL);		/* illegal pattern */
120 		if (*pattern == '-' && (c2 = pattern[1]) != EOS && c2 != ']') {
121 			if (c <= test && test <= c2)
122 				ok = 1;
123 			pattern += 2;
124 		}
125 		else if (c == test)
126 			ok = 1;
127 	}
128 	return(ok == negate ? NULL : pattern);
129 }
130