xref: /csrg-svn/lib/libc/gen/fnmatch.c (revision 42624)
139734Sbostic /*
239734Sbostic  * Copyright (c) 1989 The Regents of the University of California.
339734Sbostic  * All rights reserved.
439734Sbostic  *
539734Sbostic  * This code is derived from software contributed to Berkeley by
639734Sbostic  * Guido van Rossum.
739734Sbostic  *
8*42624Sbostic  * %sccs.include.redist.c%
939734Sbostic  */
1039734Sbostic 
1139734Sbostic #if defined(LIBC_SCCS) && !defined(lint)
12*42624Sbostic static char sccsid[] = "@(#)fnmatch.c	5.2 (Berkeley) 06/01/90";
1339734Sbostic #endif /* LIBC_SCCS and not lint */
1439734Sbostic 
1539734Sbostic /*
1639734Sbostic  * Function fnmatch() as proposed in Posix 1003.2 B.6 (rev. 9).
1739734Sbostic  * Compares a filename or pathname to a pattern.
1839734Sbostic  */
1939734Sbostic 
2039734Sbostic #include <unistd.h>
2139734Sbostic #include <string.h>
2239734Sbostic 
2339734Sbostic #define	EOS	'\0'
2439734Sbostic 
2539734Sbostic fnmatch(pattern, string, flags)
2639734Sbostic 	register char *pattern, *string;
2739734Sbostic 	int flags;
2839734Sbostic {
2939734Sbostic 	register char c;
3039734Sbostic 	char test, *rangematch();
3139734Sbostic 
3239734Sbostic 	for (;;)
3339734Sbostic 		switch (c = *pattern++) {
3439734Sbostic 		case EOS:
3539734Sbostic 			return(*string == EOS);
3639734Sbostic 		case '?':
3739734Sbostic 			if ((test = *string++) == EOS ||
3839734Sbostic 			    test == '/' && flags & FNM_PATHNAME)
3939734Sbostic 				return(0);
4039734Sbostic 			break;
4139734Sbostic 		case '*':
4239734Sbostic 			c = *pattern;
4339734Sbostic 			/* collapse multiple stars */
4439734Sbostic 			while (c == '*')
4539734Sbostic 				c = *++pattern;
4639734Sbostic 
4739734Sbostic 			/* optimize for pattern with * at end or before / */
4839734Sbostic 			if (c == EOS)
4939734Sbostic 				if (flags & FNM_PATHNAME)
5039734Sbostic 					return(!index(string, '/'));
5139734Sbostic 				else
5239734Sbostic 					return(1);
5339734Sbostic 			else if (c == '/' && flags & FNM_PATHNAME) {
5439734Sbostic 				if ((string = index(string, '/')) == NULL)
5539734Sbostic 					return(0);
5639734Sbostic 				break;
5739734Sbostic 			}
5839734Sbostic 
5939734Sbostic 			/* general case, use recursion */
6039734Sbostic 			while ((test = *string) != EOS) {
6139734Sbostic 				if (fnmatch(pattern, string, flags))
6239734Sbostic 					return(1);
6339734Sbostic 				if (test == '/' && flags & FNM_PATHNAME)
6439734Sbostic 					break;
6539734Sbostic 				++string;
6639734Sbostic 			}
6739734Sbostic 			return(0);
6839734Sbostic 		case '[':
6939734Sbostic 			if ((test = *string++) == EOS ||
7039734Sbostic 			    test == '/' && flags & FNM_PATHNAME)
7139734Sbostic 				return(0);
7239734Sbostic 			if ((pattern = rangematch(pattern, test)) == NULL)
7339734Sbostic 				return(0);
7439734Sbostic 			break;
7539734Sbostic 		case '\\':
7639734Sbostic 			if (flags & FNM_QUOTE) {
7739734Sbostic 				if ((c = *pattern++) == EOS) {
7839734Sbostic 					c = '\\';
7939734Sbostic 					--pattern;
8039734Sbostic 				}
8139734Sbostic 				if (c != *string++)
8239734Sbostic 					return(0);
8339734Sbostic 				break;
8439734Sbostic 			}
8539734Sbostic 			/* FALLTHROUGH */
8639734Sbostic 		default:
8739734Sbostic 			if (c != *string++)
8839734Sbostic 				return(0);
8939734Sbostic 			break;
9039734Sbostic 		}
9139734Sbostic }
9239734Sbostic 
9339734Sbostic static char *
9439734Sbostic rangematch(pattern, test)
9539734Sbostic 	register char *pattern, test;
9639734Sbostic {
9739734Sbostic 	register char c, c2;
9839734Sbostic 	int negate, ok;
9939734Sbostic 
10039734Sbostic 	if (negate = (*pattern == '!'))
10139734Sbostic 		++pattern;
10239734Sbostic 
10339734Sbostic 	/*
10439734Sbostic 	 * TO DO: quoting
10539734Sbostic 	 */
10639734Sbostic 
10739734Sbostic 	for (ok = 0; (c = *pattern++) != ']';) {
10839734Sbostic 		if (c == EOS)
10939734Sbostic 			return(NULL);		/* illegal pattern */
11039734Sbostic 		if (*pattern == '-' && (c2 = pattern[1]) != EOS && c2 != ']') {
11139734Sbostic 			if (c <= test && test <= c2)
11239734Sbostic 				ok = 1;
11339734Sbostic 			pattern += 2;
11439734Sbostic 		}
11539734Sbostic 		else if (c == test)
11639734Sbostic 			ok = 1;
11739734Sbostic 	}
11839734Sbostic 	return(ok == negate ? NULL : pattern);
11939734Sbostic }
120