"SfR Fresh" - the SfR Freeware/Shareware Archive 
Member "gtkfind-1.1/glob.c" of archive gtkfind-1.1.tar.gz:
As a special service "SfR Fresh" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting with prefixed line numbers.
Alternatively you can here view or download the uninterpreted source code file.
That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
1 /* glob.c */
2 /* wildcard matching routines */
3 /*
4 gtkfind - a graphical "find" program
5 Copyright (C) 1999 Matthew Grossman <mattg@oz.net>
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22
23 /* this should be just a routine to match a text string with a
24 wildcard-containing text string. I want to have the capability to save
25 portions of the match into a register, so you can access them later
26 by using \1, \2, etc. just like in sed
27
28 \0 should be the whole string
29
30 we have a max of 10 registers...should be enough...
31
32 wildcards: ? * {...} [...]
33
34 registers: (...)
35
36 you can use a \ to escape a special character
37
38 Because of this (the special capabilities we want), we are not
39 using a library
40
41 when copy_stringp == 0, registers are disabled. () are just ignored
42 in the pattern
43 */
44
45 #include "glob.h"
46
47 #define MAX_REGISTERS 10
48
49 /* globals for keeping track of registers */
50
51 static caddr_t r_start[MAX_REGISTERS];
52 static caddr_t r_end[MAX_REGISTERS];
53
54
55 static char *
56 strechr(char *s, char c)
57 /* return a pointer to the first non \-escaped character in s, or NULL */
58 {
59 char *rv = NULL;
60 char *p = NULL;
61 int match = 0;
62
63 p = s;
64
65 while(*p && !match) {
66 if(*p == c) {
67 if(c == '\\') {
68 if(*(p + 1) == '\\')
69 p += 2;
70 else
71 match++;
72 }
73 else {
74 if((p > s && *(p - 1) != '\\') || p == s)
75 match++;
76 else
77 p += 1;
78 }
79 }
80 else
81 p += 1;
82 }
83
84 if(match)
85 rv = p;
86
87 return(rv);
88 }
89
90 static char *
91 stretok(char *s, char *tokens)
92 /* do a strtok on s with tokens that are not \-escaped */
93 {
94 static char *mem = NULL;
95 char *p = NULL, *q = NULL, *r = NULL;
96 char *rv = NULL;
97
98 if(s)
99 mem = s;
100 else if(mem == NULL) /* s == NULL && mem == NULL */
101 goto DONE;
102
103 p = mem;
104 q = tokens;
105
106 do {
107 r = strechr(p, *q); /* in a real libc we couldn't do this? */
108 if(r) {
109 *r = '\0';
110 break;
111 }
112 } while(*q && q++);
113
114 if(r)
115 mem = r + 1;
116 else
117 mem = NULL;
118
119 rv = p;
120
121 DONE:
122 return(rv);
123 }
124
125
126
127 char *
128 match_squares(char *pattern, char *string)
129 /* see if the square braces in pattern match the next
130 character in string, if they do return the new pattern */
131 {
132 int negated = 0;
133 char start = 0, end = 0;
134 int success = 0;
135 char *rv = NULL;
136
137 if(*(++pattern) == '!' || *pattern == '^')
138 negated = 1;
139
140 while(1) {
141 if(*pattern == ']' &&
142 (*(pattern - 1) != '[' ||
143 *(pattern + 1) != ']'))
144 break; /* you can include a ']' by putting it first or last */
145
146 if(success) {
147 pattern++;
148 continue; /* we've already matched, and now we are just searching
149 for the last ] */
150 }
151
152 else if((*pattern == '-') &&
153 (*(pattern - 1) != '[' &&
154 *(pattern + 1) != ']')) {
155
156 /* this is a "-" used as a range */
157
158 start = *(pattern - 1) + 1;
159 end = *(pattern + 1);
160 while(start <= end) {
161 if(start++ == *string) {
162 success = 1;
163 }
164 }
165 pattern += 1;
166 }
167 if(*pattern == *string)
168 success = 1;
169
170 pattern++;
171 }
172
173 if((success && !negated) ||
174 (!success && negated))
175 rv = pattern + 1;
176 else
177 rv = NULL;
178
179 return(rv);
180 }
181
182 int
183 glob(char *pattern, char *string, char **registers, int c_reg)
184 /* glob pattern to string, return 1 if it matches, 0 if it doesn't */
185 {
186 int rv = 0;
187
188 if(*pattern == '\0' && *string == '\0')
189 rv = 1; /* this case occurs sometimes, as long as both strings
190 run out at the same time we know that they matched previously
191 */
192
193 else if(*pattern == '\\') {
194 if(*(pattern + 1) == *string)
195 rv = glob(pattern + 2, string + 1, registers, c_reg);
196 else
197 rv = 0;
198 }
199
200 else if(*pattern == '(') {
201 /* we always know where the register starts, we just don't know
202 where it ends */
203 if(r_start[c_reg]) {
204 #ifdef DEBUG
205 fprintf(stderr, "glob: registers cannot be nested!\n");
206 #endif
207 rv = 0;
208 }
209 else {
210 r_start[c_reg] = (caddr_t)string;
211 if(glob(pattern + 1, string, registers, c_reg)) {
212 rv = 1;
213 }
214 }
215 }
216
217 else if(*pattern == ')') {
218 /* deal with trailing stars */
219 if(*(pattern + 1) == '\0' && *(pattern - 1) == '*') {
220 rv = 1;
221 r_end[c_reg] = (caddr_t)(string + strlen(string));
222
223 if(registers)
224 registers[c_reg] = copy_string((char *)r_start[c_reg],
225 (char *)r_end[c_reg]);
226 }
227 else if(glob(pattern + 1, string, registers, c_reg + 1)) {
228 rv = 1;
229
230 /* we already know this pattern matches, so we can put it into
231 the register with no fear... */
232
233 r_end[c_reg] = (caddr_t)string;
234
235 if(registers)
236 registers[c_reg] = copy_string((char *)r_start[c_reg],
237 (char *)r_end[c_reg]);
238 }
239 }
240
241
242 else if(*pattern == '?') {
243 rv = glob(pattern + 1, string + 1, registers, c_reg);
244 }
245
246 else if(*pattern == '*') {
247 while(*(pattern + 1) == '*')
248 pattern++; /* eat up extra '*' */
249 if(strlen(pattern) == 1) {
250 rv = 1;
251 }
252 else {
253 while(*string) {
254 if(glob(pattern + 1, string++, registers, c_reg)) {
255 rv = 1;
256 }
257 }
258 }
259 }
260
261 else if(*pattern == '[') {
262 pattern = match_squares(pattern, string);
263 if(pattern)
264 rv = glob(pattern, string + 1, registers, c_reg);
265 else
266 goto DONE;
267 }
268
269 else if(*pattern == '{') {
270 /* best way to handle this:
271 dynamically make up a pattern and match it */
272 char *tmp = NULL, *q = NULL;
273 char *copy = NULL;
274 char *s = NULL;
275 char *last_brace = NULL;
276 int i = 0;
277
278 copy = (char *)alloca(strlen(pattern) + 1);
279 if(!copy)
280 goto DONE;
281 strcpy(copy, pattern + 1);
282 last_brace = strechr(copy, '}');
283 if(!last_brace)
284 goto DONE;
285 *last_brace = '\0';
286
287 q = stretok(copy, ",");
288
289 s = strechr(pattern, '}'); /* get the rest of the pattern after the { */
290 s++;
291
292 if(!s || !q || q >= s) {
293 goto DONE;
294 }
295
296 i = strlen(q) + strlen(s) + 1;
297 tmp = (char *)malloc(sizeof(char) * i);
298 strcpy(tmp, q);
299 strcat(tmp, s); /* make up a pattern and try matching it, if we fail
300 make up the next one, etc. */
301 while((rv = glob(tmp, string, registers, c_reg)) == 0) {
302 q = stretok(NULL, ",");
303 if(!q || q >= s)
304 break;
305 else {
306 i = strlen(q) + strlen(s) + 1;
307 tmp = (char *)realloc(tmp,sizeof(char) * i);
308 strcpy(tmp, q);
309 strcat(tmp, s);
310 }
311 }
312 if(tmp)
313 free(tmp);
314 }
315
316
317 else if(strcmp(pattern, string) == 0)
318 rv = 1;
319
320 else if(*pattern == *string)
321 rv = glob(pattern + 1, string + 1, registers, c_reg);
322
323 DONE:
324 return(rv);
325 }
326
327 char **
328 glob_string(char *pattern, char *string, int copy_stringp)
329 /* the user-visible function, returns the registers, with the
330 string in register[0] if copy_stringp */
331 {
332 char **registers = NULL;
333
334 if(copy_stringp) {
335 registers = allocate_glob_registers();
336 memset(r_start, 0, MAX_REGISTERS * sizeof(caddr_t));
337 memset(r_end, 0, MAX_REGISTERS * sizeof(caddr_t));
338
339 registers[0] = copy_string(string, string + strlen(string));
340 }
341
342 if(strcmp(pattern, "*") == 0 || glob(pattern, string, registers, 1)) {
343 if(copy_stringp)
344 return(registers);
345 else
346 return((char **)1);
347 }
348 else {
349 if(registers)
350 free_glob_registers(registers);
351 return(NULL);
352 }
353 }
354
355 char **
356 allocate_glob_registers()
357 {
358 char **rv = NULL;
359
360 rv = (char **)calloc(1, MAX_REGISTERS * sizeof(char *));
361 return(rv);
362 }
363
364 void
365 free_glob_registers(char **registers)
366 /* use this to free glob registers */
367 {
368 int i = 0;
369
370 if(registers) {
371 for(i = 0; i < MAX_REGISTERS; i++) {
372 if(registers[i])
373 free(registers[i]);
374 }
375 free(registers);
376 }
377
378 return;
379 }
380
381 char *
382 copy_string(char *start, char *end)
383 /* allocate string between start and end, return it */
384 {
385 char *rv = NULL;
386 int length = 0;
387
388 length = (end - start) + 1;
389 rv = (char *)malloc(length * sizeof(char));
390
391 strncpy(rv, start, length - 1);
392 rv[length - 1] = '\0';
393
394 return(rv);
395 }
396
397
398 #ifdef GLOBTEST
399
400
401 int
402 main(int argc, char *argv[])
403 {
404 char **registers = NULL;
405 int i = 0;
406
407 if((registers = glob_string(argv[1], argv[2], 1)) != NULL)
408 printf("%s matches %s!\n", argv[1], argv[2]);
409 else
410 printf("%s doesn't match %s\n", argv[1], argv[2]);
411
412 for(i = 0; i < MAX_REGISTERS; i++) {
413 if(registers && registers[i])
414 printf("registers[%d] = %s\n", i, registers[i]);
415 }
416
417 free_glob_registers(registers);
418
419 exit(0);
420 }
421
422 #endif /* GLOBTEST */