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