386BSD 0.1 development
[unix-history] / usr / src / usr.bin / tar / wildmat.c
CommitLineData
f87489ac
WJ
1/* Wildcard matching routines.
2 Copyright (C) 1988 Free Software Foundation
3
4This file is part of GNU Tar.
5
6GNU Tar is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 1, or (at your option)
9any later version.
10
11GNU Tar is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Tar; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20/*
21 * @(#)wildmat.c 1.3 87/11/06
22 *
23From: rs@mirror.TMC.COM (Rich Salz)
24Newsgroups: net.sources
25Subject: Small shell-style pattern matcher
26Message-ID: <596@mirror.TMC.COM>
27Date: 27 Nov 86 00:06:40 GMT
28
29There have been several regular-expression subroutines and one or two
30filename-globbing routines in mod.sources. They handle lots of
31complicated patterns. This small piece of code handles the *?[]\
32wildcard characters the way the standard Unix(tm) shells do, with the
33addition that "[^.....]" is an inverse character class -- it matches
34any character not in the range ".....". Read the comments for more
35info.
36
37For my application, I had first ripped off a copy of the "glob" routine
38from within the find source, but that code is bad news: it recurses
39on every character in the pattern. I'm putting this replacement in the
40public domain. It's small, tight, and iterative. Compile with -DTEST
41to get a test driver. After you're convinced it works, install in
42whatever way is appropriate for you.
43
44I would like to hear of bugs, but am not interested in additions; if I
45were, I'd use the code I mentioned above.
46*/
47/*
48** Do shell-style pattern matching for ?, \, [], and * characters.
49** Might not be robust in face of malformed patterns; e.g., "foo[a-"
50** could cause a segmentation violation.
51**
52** Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
53*/
54
55/*
56 * Modified 6Nov87 by John Gilmore (hoptoad!gnu) to return a "match"
57 * if the pattern is immediately followed by a "/", as well as \0.
58 * This matches what "tar" does for matching whole subdirectories.
59 *
60 * The "*" code could be sped up by only recursing one level instead
61 * of two for each trial pattern, perhaps, and not recursing at all
62 * if a literal match of the next 2 chars would fail.
63 */
64#define TRUE 1
65#define FALSE 0
66
67
68static int
69Star(s, p)
70 register char *s;
71 register char *p;
72{
73 while (wildmat(s, p) == FALSE)
74 if (*++s == '\0')
75 return(FALSE);
76 return(TRUE);
77}
78
79
80int
81wildmat(s, p)
82 register char *s;
83 register char *p;
84{
85 register int last;
86 register int matched;
87 register int reverse;
88
89 for ( ; *p; s++, p++)
90 switch (*p) {
91 case '\\':
92 /* Literal match with following character; fall through. */
93 p++;
94 default:
95 if (*s != *p)
96 return(FALSE);
97 continue;
98 case '?':
99 /* Match anything. */
100 if (*s == '\0')
101 return(FALSE);
102 continue;
103 case '*':
104 /* Trailing star matches everything. */
105 return(*++p ? Star(s, p) : TRUE);
106 case '[':
107 /* [^....] means inverse character class. */
108 if (reverse = p[1] == '^')
109 p++;
110 for (last = 0400, matched = FALSE; *++p && *p != ']'; last = *p)
111 /* This next line requires a good C compiler. */
112 if (*p == '-' ? *s <= *++p && *s >= last : *s == *p)
113 matched = TRUE;
114 if (matched == reverse)
115 return(FALSE);
116 continue;
117 }
118
119 /* For "tar" use, matches that end at a slash also work. --hoptoad!gnu */
120 return(*s == '\0' || *s == '/');
121}
122
123
124#ifdef TEST
125#include <stdio.h>
126
127extern char *gets();
128
129
130main()
131{
132 char pattern[80];
133 char text[80];
134
135 while (TRUE) {
136 printf("Enter pattern: ");
137 if (gets(pattern) == NULL)
138 break;
139 while (TRUE) {
140 printf("Enter text: ");
141 if (gets(text) == NULL)
142 exit(0);
143 if (text[0] == '\0')
144 /* Blank line; go back and get a new pattern. */
145 break;
146 printf(" %d\n", wildmat(text, pattern));
147 }
148 }
149 exit(0);
150}
151#endif /* TEST */