/* fnmatch.cc: Filename amtch Copyright 2001 Red Hat, Inc. Copyright 2001 Red Hat, Inc. Written by Robert Collins This file is part of Cygwin. This software is a copyrighted work licensed under the terms of the Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ #include #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "winsup.h" #include #include "cygerrno.h" #include /* compare pattern against string. * logic: iterate across pattern incrementing string * as appropriate. * for *, we skip across any following * or ? characters, * incrementing the string location for ?, * and then try to match the following component against the remaining string. * but allowing it to slide to the right by up to * len (rem string) - (len (remaining pattern) */ extern "C" int fnmatch (const char *pattern, const char *string, int flags) { const char *p = pattern, *s = string; char current; while ((current = *p++) != '\0') { switch (current) { case '?': if ((*s == '\0') || ((flags & FNM_PATHNAME) && *s == '/') || (((flags & FNM_PERIOD) && *s == '.') && ((s == string) || ((flags & FNM_PATHNAME) && s[-1] == '/')))) return FNM_NOMATCH; s++; break; case '*': if (*s == '\0') return 0; // * matches NULL strings. if ((flags & FNM_PERIOD) && *s == '.' && ((s == string) || ((flags & FNM_PATHNAME) && s[-1] == '/'))) return FNM_NOMATCH; /* walk through any wildcards - ** == *, and *? = * with a length minimum. */ for (current = *p++; current == '*' || current == '?'; current = *p++) { if ((flags & FNM_PATHNAME) && *s == '/') return FNM_NOMATCH; // Can't get a . here, it must follow / caught aboce if (current == '?') { if (*s == '\0') return FNM_NOMATCH; else // use up a character. s++; } } if (current == '\0') return 0; // success --p; // get back a pointer to the remaining pattern if (current == '\\' && !(flags & FNM_NOESCAPE)) { current = p[1]; // preserve the location if (current == '\0') return FNM_NOMATCH; } while (*s) { int subflags = flags & ~FNM_PERIOD; if ((flags & FNM_PATHNAME) && *s == '/') return FNM_NOMATCH; if (current == *s && (fnmatch (p, s, subflags) == 0)) return 0; // recursion worked ++s; } return FNM_NOMATCH; case '[': // Grr regexp time return FNM_NOMATCH; break; // '!' is the negatopr, not '^' as usual case '\\': if (!(flags & FNM_NOESCAPE)) { current = *p++; if (current == '\0') // \ without character return FNM_NOMATCH; } if (*s == '\0' || current != *s++) return FNM_NOMATCH; break; case '|': /* fallthru */ case '&': /* fallthru */ case ';': /* fallthru */ case '<': /* fallthru */ case '>': /* fallthru */ case '(': /* fallthru */ case ')': /* fallthru */ case '$': /* fallthru */ case '\"': /* fallthru */ case ' ': /* fallthru */ case '\t': /* fallthru */ case '\n': /* fallthru */ case '#': /* fallthru *//* these next 4 may need to be allowed */ case '~': /* fallthru */ case '=': /* fallthru */ case '%': /* These characters _have_ to be escaped according to IEEE P1003.1, Draft 6, April 2001/ Open Group Technical Standard, Issue 6 2.13.1 */ return FNM_NOMATCH; default: if (current != *s++) return FNM_NOMATCH; } } if (*s == '\0') return 0; // Gotta love the non-posix extensions required to satisfy GNU AC tests if(*s == '/' && (flags & FNM_LEADING_DIR)) return 0; return FNM_NOMATCH; }