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.4 (Berkeley) 02/23/91"; 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 static char * 26 rangematch(pattern, test) 27 register char *pattern, test; 28 { 29 register char c, c2; 30 int negate, ok; 31 32 if (negate = (*pattern == '!')) 33 ++pattern; 34 35 /* 36 * TO DO: quoting 37 */ 38 39 for (ok = 0; (c = *pattern++) != ']';) { 40 if (c == EOS) 41 return(NULL); /* illegal pattern */ 42 if (*pattern == '-' && (c2 = pattern[1]) != EOS && c2 != ']') { 43 if (c <= test && test <= c2) 44 ok = 1; 45 pattern += 2; 46 } 47 else if (c == test) 48 ok = 1; 49 } 50 return(ok == negate ? NULL : pattern); 51 } 52 53 fnmatch(pattern, string, flags) 54 register const char *pattern; 55 register const char *string; 56 int flags; 57 { 58 register char c; 59 char test, *rangematch(); 60 61 for (;;) 62 switch (c = *pattern++) { 63 case EOS: 64 return(*string == EOS); 65 case '?': 66 if ((test = *string++) == EOS || 67 test == '/' && flags & FNM_PATHNAME) 68 return(0); 69 break; 70 case '*': 71 c = *pattern; 72 /* collapse multiple stars */ 73 while (c == '*') 74 c = *++pattern; 75 76 /* optimize for pattern with * at end or before / */ 77 if (c == EOS) 78 if (flags & FNM_PATHNAME) 79 return(!index(string, '/')); 80 else 81 return(1); 82 else if (c == '/' && flags & FNM_PATHNAME) { 83 if ((string = index(string, '/')) == NULL) 84 return(0); 85 break; 86 } 87 88 /* general case, use recursion */ 89 while ((test = *string) != EOS) { 90 if (fnmatch(pattern, string, flags)) 91 return(1); 92 if (test == '/' && flags & FNM_PATHNAME) 93 break; 94 ++string; 95 } 96 return(0); 97 case '[': 98 if ((test = *string++) == EOS || 99 test == '/' && flags & FNM_PATHNAME) 100 return(0); 101 if ((pattern = rangematch(pattern, test)) == NULL) 102 return(0); 103 break; 104 case '\\': 105 if (flags & FNM_QUOTE) { 106 if ((c = *pattern++) == EOS) { 107 c = '\\'; 108 --pattern; 109 } 110 if (c != *string++) 111 return(0); 112 break; 113 } 114 /* FALLTHROUGH */ 115 default: 116 if (c != *string++) 117 return(0); 118 break; 119 } 120 } 121