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.3 (Berkeley) 06/23/90"; 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 char *pattern, *string; 55 int flags; 56 { 57 register char c; 58 char test, *rangematch(); 59 60 for (;;) 61 switch (c = *pattern++) { 62 case EOS: 63 return(*string == EOS); 64 case '?': 65 if ((test = *string++) == EOS || 66 test == '/' && flags & FNM_PATHNAME) 67 return(0); 68 break; 69 case '*': 70 c = *pattern; 71 /* collapse multiple stars */ 72 while (c == '*') 73 c = *++pattern; 74 75 /* optimize for pattern with * at end or before / */ 76 if (c == EOS) 77 if (flags & FNM_PATHNAME) 78 return(!index(string, '/')); 79 else 80 return(1); 81 else if (c == '/' && flags & FNM_PATHNAME) { 82 if ((string = index(string, '/')) == NULL) 83 return(0); 84 break; 85 } 86 87 /* general case, use recursion */ 88 while ((test = *string) != EOS) { 89 if (fnmatch(pattern, string, flags)) 90 return(1); 91 if (test == '/' && flags & FNM_PATHNAME) 92 break; 93 ++string; 94 } 95 return(0); 96 case '[': 97 if ((test = *string++) == EOS || 98 test == '/' && flags & FNM_PATHNAME) 99 return(0); 100 if ((pattern = rangematch(pattern, test)) == NULL) 101 return(0); 102 break; 103 case '\\': 104 if (flags & FNM_QUOTE) { 105 if ((c = *pattern++) == EOS) { 106 c = '\\'; 107 --pattern; 108 } 109 if (c != *string++) 110 return(0); 111 break; 112 } 113 /* FALLTHROUGH */ 114 default: 115 if (c != *string++) 116 return(0); 117 break; 118 } 119 } 120