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 * Redistribution and use in source and binary forms are permitted 9 * provided that the above copyright notice and this paragraph are 10 * duplicated in all such forms and that any documentation, 11 * advertising materials, and other materials related to such 12 * distribution and use acknowledge that the software was developed 13 * by the University of California, Berkeley. The name of the 14 * University may not be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 */ 20 21 #if defined(LIBC_SCCS) && !defined(lint) 22 static char sccsid[] = "@(#)fnmatch.c 5.1 (Berkeley) 12/19/89"; 23 #endif /* LIBC_SCCS and not lint */ 24 25 /* 26 * Function fnmatch() as proposed in Posix 1003.2 B.6 (rev. 9). 27 * Compares a filename or pathname to a pattern. 28 */ 29 30 #include <unistd.h> 31 #include <string.h> 32 33 #define EOS '\0' 34 35 fnmatch(pattern, string, flags) 36 register char *pattern, *string; 37 int flags; 38 { 39 register char c; 40 char test, *rangematch(); 41 42 for (;;) 43 switch (c = *pattern++) { 44 case EOS: 45 return(*string == EOS); 46 case '?': 47 if ((test = *string++) == EOS || 48 test == '/' && flags & FNM_PATHNAME) 49 return(0); 50 break; 51 case '*': 52 c = *pattern; 53 /* collapse multiple stars */ 54 while (c == '*') 55 c = *++pattern; 56 57 /* optimize for pattern with * at end or before / */ 58 if (c == EOS) 59 if (flags & FNM_PATHNAME) 60 return(!index(string, '/')); 61 else 62 return(1); 63 else if (c == '/' && flags & FNM_PATHNAME) { 64 if ((string = index(string, '/')) == NULL) 65 return(0); 66 break; 67 } 68 69 /* general case, use recursion */ 70 while ((test = *string) != EOS) { 71 if (fnmatch(pattern, string, flags)) 72 return(1); 73 if (test == '/' && flags & FNM_PATHNAME) 74 break; 75 ++string; 76 } 77 return(0); 78 case '[': 79 if ((test = *string++) == EOS || 80 test == '/' && flags & FNM_PATHNAME) 81 return(0); 82 if ((pattern = rangematch(pattern, test)) == NULL) 83 return(0); 84 break; 85 case '\\': 86 if (flags & FNM_QUOTE) { 87 if ((c = *pattern++) == EOS) { 88 c = '\\'; 89 --pattern; 90 } 91 if (c != *string++) 92 return(0); 93 break; 94 } 95 /* FALLTHROUGH */ 96 default: 97 if (c != *string++) 98 return(0); 99 break; 100 } 101 } 102 103 static char * 104 rangematch(pattern, test) 105 register char *pattern, test; 106 { 107 register char c, c2; 108 int negate, ok; 109 110 if (negate = (*pattern == '!')) 111 ++pattern; 112 113 /* 114 * TO DO: quoting 115 */ 116 117 for (ok = 0; (c = *pattern++) != ']';) { 118 if (c == EOS) 119 return(NULL); /* illegal pattern */ 120 if (*pattern == '-' && (c2 = pattern[1]) != EOS && c2 != ']') { 121 if (c <= test && test <= c2) 122 ok = 1; 123 pattern += 2; 124 } 125 else if (c == test) 126 ok = 1; 127 } 128 return(ok == negate ? NULL : pattern); 129 } 130