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