/* Copyright (C) 1988 Free Software Foundation GNU tar is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to anyone for the consequences of using it or for whether it serves any particular purpose or works at all, unless he says so in writing. Refer to the GNU tar General Public License for full details. Everyone is granted permission to copy, modify and redistribute GNU tar, but only under the conditions described in the GNU tar General Public License. A copy of this license is supposed to have been given to you along with GNU tar so you can know your rights and responsibilities. It should be in a file named COPYING. Among other things, the copyright notice and this notice must be preserved on all copies. In other words, go ahead and share GNU tar, but don't try to stop anyone else from sharing it farther. Help stamp out software hoarding! */ /* * @(#)wildmat.c 1.3 87/11/06 * From: rs@mirror.TMC.COM (Rich Salz) Newsgroups: net.sources Subject: Small shell-style pattern matcher Message-ID: <596@mirror.TMC.COM> Date: 27 Nov 86 00:06:40 GMT There have been several regular-expression subroutines and one or two filename-globbing routines in mod.sources. They handle lots of complicated patterns. This small piece of code handles the *?[]\ wildcard characters the way the standard Unix(tm) shells do, with the addition that "[^.....]" is an inverse character class -- it matches any character not in the range ".....". Read the comments for more info. For my application, I had first ripped off a copy of the "glob" routine from within the find(1) source, but that code is bad news: it recurses on every character in the pattern. I'm putting this replacement in the public domain. It's small, tight, and iterative. Compile with -DTEST to get a test driver. After you're convinced it works, install in whatever way is appropriate for you. I would like to hear of bugs, but am not interested in additions; if I were, I'd use the code I mentioned above. */ /* ** Do shell-style pattern matching for ?, \, [], and * characters. ** Might not be robust in face of malformed patterns; e.g., "foo[a-" ** could cause a segmentation violation. ** ** Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986. */ /* * Modified 6Nov87 by John Gilmore (hoptoad!gnu) to return a "match" * if the pattern is immediately followed by a "/", as well as \0. * This matches what "tar" does for matching whole subdirectories. * * The "*" code could be sped up by only recursing one level instead * of two for each trial pattern, perhaps, and not recursing at all * if a literal match of the next 2 chars would fail. */ #define TRUE 1 #define FALSE 0 static int Star(s, p) register char *s; register char *p; { while (wildmat(s, p) == FALSE) if (*++s == '\0') return(FALSE); return(TRUE); } int wildmat(s, p) register char *s; register char *p; { register int last; register int matched; register int reverse; for ( ; *p; s++, p++) switch (*p) { case '\\': /* Literal match with following character; fall through. */ p++; default: if (*s != *p) return(FALSE); continue; case '?': /* Match anything. */ if (*s == '\0') return(FALSE); continue; case '*': /* Trailing star matches everything. */ return(*++p ? Star(s, p) : TRUE); case '[': /* [^....] means inverse character class. */ if (reverse = p[1] == '^') p++; for (last = 0400, matched = FALSE; *++p && *p != ']'; last = *p) /* This next line requires a good C compiler. */ if (*p == '-' ? *s <= *++p && *s >= last : *s == *p) matched = TRUE; if (matched == reverse) return(FALSE); continue; } /* For "tar" use, matches that end at a slash also work. --hoptoad!gnu */ return(*s == '\0' || *s == '/'); } #ifdef TEST #include extern char *gets(); main() { char pattern[80]; char text[80]; while (TRUE) { printf("Enter pattern: "); if (gets(pattern) == NULL) break; while (TRUE) { printf("Enter text: "); if (gets(text) == NULL) exit(0); if (text[0] == '\0') /* Blank line; go back and get a new pattern. */ break; printf(" %d\n", wildmat(text, pattern)); } } exit(0); } #endif /* TEST */