Commit | Line | Data |
---|---|---|
f87489ac WJ |
1 | /* Wildcard matching routines. |
2 | Copyright (C) 1988 Free Software Foundation | |
3 | ||
4 | This file is part of GNU Tar. | |
5 | ||
6 | GNU Tar is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
8 | the Free Software Foundation; either version 1, or (at your option) | |
9 | any later version. | |
10 | ||
11 | GNU Tar is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with GNU Tar; see the file COPYING. If not, write to | |
18 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
19 | ||
20 | /* | |
21 | * @(#)wildmat.c 1.3 87/11/06 | |
22 | * | |
23 | From: rs@mirror.TMC.COM (Rich Salz) | |
24 | Newsgroups: net.sources | |
25 | Subject: Small shell-style pattern matcher | |
26 | Message-ID: <596@mirror.TMC.COM> | |
27 | Date: 27 Nov 86 00:06:40 GMT | |
28 | ||
29 | There have been several regular-expression subroutines and one or two | |
30 | filename-globbing routines in mod.sources. They handle lots of | |
31 | complicated patterns. This small piece of code handles the *?[]\ | |
32 | wildcard characters the way the standard Unix(tm) shells do, with the | |
33 | addition that "[^.....]" is an inverse character class -- it matches | |
34 | any character not in the range ".....". Read the comments for more | |
35 | info. | |
36 | ||
37 | For my application, I had first ripped off a copy of the "glob" routine | |
38 | from within the find source, but that code is bad news: it recurses | |
39 | on every character in the pattern. I'm putting this replacement in the | |
40 | public domain. It's small, tight, and iterative. Compile with -DTEST | |
41 | to get a test driver. After you're convinced it works, install in | |
42 | whatever way is appropriate for you. | |
43 | ||
44 | I would like to hear of bugs, but am not interested in additions; if I | |
45 | were, 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 | ||
68 | static int | |
69 | Star(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 | ||
80 | int | |
81 | wildmat(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 | ||
127 | extern char *gets(); | |
128 | ||
129 | ||
130 | main() | |
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 */ |