CSL 5.2

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

pattern_match.c
Go to the documentation of this file.
1 /* Open SoundControl kit in C++ */
2 /* Copyright (C) 2002-2004 libOSC++ contributors. See AUTHORS */
3 /* */
4 /* This library is free software; you can redistribute it and/or */
5 /* modify it under the terms of the GNU Lesser General Public */
6 /* License as published by the Free Software Foundation; either */
7 /* version 2.1 of the License, or (at your option) any later version. */
8 /* */
9 /* This library is distributed in the hope that it will be useful, */
10 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
11 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
12 /* Lesser General Public License for more details. */
13 /* */
14 /* You should have received a copy of the GNU Lesser General Public */
15 /* License along with this library; if not, write to the Free Software */
16 /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
17 /* */
18 /* For questions regarding this program contact */
19 /* Daniel Holth <dholth@fastmail.fm> or visit */
20 /* http://wiretap.stetson.edu/ */
21
22 /* In the sprit of the public domain, my modifications to this file are also */
23 /* dedicated to the public domain. Daniel Holth, Oct. 2004 */
24
25 /* ChangeLog:
26 *
27 * 2004-10-29 Import, convert to C++, begin OSC syntax changes. -dwh
28 * OSC syntax changes are now working, needs more testing.
29 *
30 */
31
32 // Original header and syntax:
33
34 /*
35 * robust glob pattern matcher
36 * ozan s. yigit/dec 1994
37 * public domain
38 *
39 * glob patterns:
40 * * matches zero or more characters
41 * ? matches any single character
42 * [set] matches any character in the set
43 * [^set] matches any character NOT in the set
44 * where a set is a group of characters or ranges. a range
45 * is written as two characters seperated with a hyphen: a-z denotes
46 * all characters between a to z inclusive.
47 * [-set] set matches a literal hypen and any character in the set
48 * []set] matches a literal close bracket and any character in the set
49 *
50 * char matches itself except where char is '*' or '?' or '['
51 * \char matches char, including any pattern character
52 *
53 * examples:
54 * a*c ac abc abbc ...
55 * a?c acc abc aXc ...
56 * a[a-z]c aac abc acc ...
57 * a[-a-z]c a-c aac abc ...
58 *
59 * $Log$
60 * Revision 1.1 2004/11/19 23:00:57 theno23
61 * Added lo_send_timestamped
62 *
63 * Revision 1.3 1995/09/14 23:24:23 oz
64 * removed boring test/main code.
65 *
66 * Revision 1.2 94/12/11 10:38:15 oz
67 * cset code fixed. it is now robust and interprets all
68 * variations of cset [i think] correctly, including [z-a] etc.
69 *
70 * Revision 1.1 94/12/08 12:45:23 oz
71 * Initial revision
72 */
73
74 #include "lo/lo.h"
75
76 #ifndef NEGATE
77 #define NEGATE '!'
78 #endif
79
80 #ifndef true
81 #define true 1
82 #endif
83 #ifndef false
84 #define false 0
85 #endif
86
87 int lo_pattern_match(const char *str, const char *p)
88 {
89 int negate;
90 int match;
91 char c;
92
93 while (*p) {
94 if (!*str && *p != '*')
95 return false;
96
97 switch (c = *p++) {
98
99 case '*':
100 while (*p == '*' && *p != '/')
101 p++;
102
103 if (!*p)
104 return true;
105
106 // if (*p != '?' && *p != '[' && *p != '\\')
107 if (*p != '?' && *p != '[' && *p != '{')
108 while (*str && *p != *str)
109 str++;
110
111 while (*str) {
112 if (lo_pattern_match(str, p))
113 return true;
114 str++;
115 }
116 return false;
117
118 case '?':
119 if (*str)
120 break;
121 return false;
122 /*
123 * set specification is inclusive, that is [a-z] is a, z and
124 * everything in between. this means [z-a] may be interpreted
125 * as a set that contains z, a and nothing in between.
126 */
127 case '[':
128 if (*p != NEGATE)
129 negate = false;
130 else {
131 negate = true;
132 p++;
133 }
134
135 match = false;
136
137 while (!match && (c = *p++)) {
138 if (!*p)
139 return false;
140 if (*p == '-') { /* c-c */
141 if (!*++p)
142 return false;
143 if (*p != ']') {
144 if (*str == c || *str == *p ||
145 (*str > c && *str < *p))
146 match = true;
147 }
148 else { /* c-] */
149 if (*str >= c)
150 match = true;
151 break;
152 }
153 }
154 else { /* cc or c] */
155 if (c == *str)
156 match = true;
157 if (*p != ']') {
158 if (*p == *str)
159 match = true;
160 }
161 else
162 break;
163 }
164 }
165
166 if (negate == match)
167 return false;
168 /*
169 * if there is a match, skip past the cset and continue on
170 */
171 while (*p && *p != ']')
172 p++;
173 if (!*p++) /* oops! */
174 return false;
175 break;
176
177 /*
178 * {astring,bstring,cstring}
179 */
180 case '{':
181 {
182 // *p is now first character in the {brace list}
183 const char *place = str; // to backtrack
184 const char *remainder = p; // to forwardtrack
185
186 // find the end of the brace list
187 while (*remainder && *remainder != '}')
188 remainder++;
189 if (!*remainder++) /* oops! */
190 return false;
191
192 c = *p++;
193
194 while (c) {
195 if (c == ',') {
196 if(lo_pattern_match(str, remainder)) {
197 return true;
198 } else {
199 // backtrack on test string
200 str = place;
201 // continue testing,
202 // skip comma
203 if (!*p++) // oops
204 return false;
205 }
206 }
207 else if (c == '}') {
208 // continue normal pattern matching
209 if (!*p && !*str) return true;
210 str--; // str is incremented again below
211 break;
212 } else if (c == *str) {
213 str++;
214 if (!*str && *remainder)
215 return false;
216 } else { // skip to next comma
217 str = place;
218 while (*p != ',' && *p != '}' && *p)
219 p++;
220 if (*p == ',')
221 p++;
222 else if (*p == '}') {
223 return false;
224 }
225 }
226 c = *p++;
227 }
228 }
229
230 break;
231
232 /* Not part of OSC pattern matching
233 case '\\':
234 if (*p)
235 c = *p++;
236 */
237
238 default:
239 if (c != *str)
240 return false;
241 break;
242
243 }
244 str++;
245 }
246
247 return !*str;
248 }