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 * 842624Sbostic * %sccs.include.redist.c% 939734Sbostic */ 1039734Sbostic 1139734Sbostic #if defined(LIBC_SCCS) && !defined(lint) 12*43528Sbostic static char sccsid[] = "@(#)fnmatch.c 5.3 (Berkeley) 06/23/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 25*43528Sbostic static char * 26*43528Sbostic rangematch(pattern, test) 27*43528Sbostic register char *pattern, test; 28*43528Sbostic { 29*43528Sbostic register char c, c2; 30*43528Sbostic int negate, ok; 31*43528Sbostic 32*43528Sbostic if (negate = (*pattern == '!')) 33*43528Sbostic ++pattern; 34*43528Sbostic 35*43528Sbostic /* 36*43528Sbostic * TO DO: quoting 37*43528Sbostic */ 38*43528Sbostic 39*43528Sbostic for (ok = 0; (c = *pattern++) != ']';) { 40*43528Sbostic if (c == EOS) 41*43528Sbostic return(NULL); /* illegal pattern */ 42*43528Sbostic if (*pattern == '-' && (c2 = pattern[1]) != EOS && c2 != ']') { 43*43528Sbostic if (c <= test && test <= c2) 44*43528Sbostic ok = 1; 45*43528Sbostic pattern += 2; 46*43528Sbostic } 47*43528Sbostic else if (c == test) 48*43528Sbostic ok = 1; 49*43528Sbostic } 50*43528Sbostic return(ok == negate ? NULL : pattern); 51*43528Sbostic } 52*43528Sbostic 5339734Sbostic fnmatch(pattern, string, flags) 5439734Sbostic register char *pattern, *string; 5539734Sbostic int flags; 5639734Sbostic { 5739734Sbostic register char c; 5839734Sbostic char test, *rangematch(); 5939734Sbostic 6039734Sbostic for (;;) 6139734Sbostic switch (c = *pattern++) { 6239734Sbostic case EOS: 6339734Sbostic return(*string == EOS); 6439734Sbostic case '?': 6539734Sbostic if ((test = *string++) == EOS || 6639734Sbostic test == '/' && flags & FNM_PATHNAME) 6739734Sbostic return(0); 6839734Sbostic break; 6939734Sbostic case '*': 7039734Sbostic c = *pattern; 7139734Sbostic /* collapse multiple stars */ 7239734Sbostic while (c == '*') 7339734Sbostic c = *++pattern; 7439734Sbostic 7539734Sbostic /* optimize for pattern with * at end or before / */ 7639734Sbostic if (c == EOS) 7739734Sbostic if (flags & FNM_PATHNAME) 7839734Sbostic return(!index(string, '/')); 7939734Sbostic else 8039734Sbostic return(1); 8139734Sbostic else if (c == '/' && flags & FNM_PATHNAME) { 8239734Sbostic if ((string = index(string, '/')) == NULL) 8339734Sbostic return(0); 8439734Sbostic break; 8539734Sbostic } 8639734Sbostic 8739734Sbostic /* general case, use recursion */ 8839734Sbostic while ((test = *string) != EOS) { 8939734Sbostic if (fnmatch(pattern, string, flags)) 9039734Sbostic return(1); 9139734Sbostic if (test == '/' && flags & FNM_PATHNAME) 9239734Sbostic break; 9339734Sbostic ++string; 9439734Sbostic } 9539734Sbostic return(0); 9639734Sbostic case '[': 9739734Sbostic if ((test = *string++) == EOS || 9839734Sbostic test == '/' && flags & FNM_PATHNAME) 9939734Sbostic return(0); 10039734Sbostic if ((pattern = rangematch(pattern, test)) == NULL) 10139734Sbostic return(0); 10239734Sbostic break; 10339734Sbostic case '\\': 10439734Sbostic if (flags & FNM_QUOTE) { 10539734Sbostic if ((c = *pattern++) == EOS) { 10639734Sbostic c = '\\'; 10739734Sbostic --pattern; 10839734Sbostic } 10939734Sbostic if (c != *string++) 11039734Sbostic return(0); 11139734Sbostic break; 11239734Sbostic } 11339734Sbostic /* FALLTHROUGH */ 11439734Sbostic default: 11539734Sbostic if (c != *string++) 11639734Sbostic return(0); 11739734Sbostic break; 11839734Sbostic } 11939734Sbostic } 120