diff options
Diffstat (limited to 'openbsd-compat/glob.c')
-rw-r--r-- | openbsd-compat/glob.c | 859 |
1 files changed, 859 insertions, 0 deletions
diff --git a/openbsd-compat/glob.c b/openbsd-compat/glob.c new file mode 100644 index 000000000..2e2551866 --- /dev/null +++ b/openbsd-compat/glob.c | |||
@@ -0,0 +1,859 @@ | |||
1 | /* | ||
2 | * Copyright (c) 1989, 1993 | ||
3 | * The Regents of the University of California. All rights reserved. | ||
4 | * | ||
5 | * This code is derived from software contributed to Berkeley by | ||
6 | * Guido van Rossum. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * 1. Redistributions of source code must retain the above copyright | ||
12 | * notice, this list of conditions and the following disclaimer. | ||
13 | * 2. Redistributions in binary form must reproduce the above copyright | ||
14 | * notice, this list of conditions and the following disclaimer in the | ||
15 | * documentation and/or other materials provided with the distribution. | ||
16 | * 3. All advertising materials mentioning features or use of this software | ||
17 | * must display the following acknowledgement: | ||
18 | * This product includes software developed by the University of | ||
19 | * California, Berkeley and its contributors. | ||
20 | * 4. Neither the name of the University nor the names of its contributors | ||
21 | * may be used to endorse or promote products derived from this software | ||
22 | * without specific prior written permission. | ||
23 | * | ||
24 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | ||
25 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | ||
28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
34 | * SUCH DAMAGE. | ||
35 | */ | ||
36 | |||
37 | #include "includes.h" | ||
38 | #include <ctype.h> | ||
39 | |||
40 | #if !defined(HAVE_GLOB) || !defined(GLOB_HAS_ALTDIRFUNC) | ||
41 | |||
42 | #if defined(LIBC_SCCS) && !defined(lint) | ||
43 | #if 0 | ||
44 | static char sccsid[] = "@(#)glob.c 8.3 (Berkeley) 10/13/93"; | ||
45 | #else | ||
46 | static char rcsid[] = "$OpenBSD: glob.c,v 1.8 1998/08/14 21:39:30 deraadt Exp $"; | ||
47 | #endif | ||
48 | #endif /* LIBC_SCCS and not lint */ | ||
49 | |||
50 | /* | ||
51 | * glob(3) -- a superset of the one defined in POSIX 1003.2. | ||
52 | * | ||
53 | * The [!...] convention to negate a range is supported (SysV, Posix, ksh). | ||
54 | * | ||
55 | * Optional extra services, controlled by flags not defined by POSIX: | ||
56 | * | ||
57 | * GLOB_QUOTE: | ||
58 | * Escaping convention: \ inhibits any special meaning the following | ||
59 | * character might have (except \ at end of string is retained). | ||
60 | * GLOB_MAGCHAR: | ||
61 | * Set in gl_flags if pattern contained a globbing character. | ||
62 | * GLOB_NOMAGIC: | ||
63 | * Same as GLOB_NOCHECK, but it will only append pattern if it did | ||
64 | * not contain any magic characters. [Used in csh style globbing] | ||
65 | * GLOB_ALTDIRFUNC: | ||
66 | * Use alternately specified directory access functions. | ||
67 | * GLOB_TILDE: | ||
68 | * expand ~user/foo to the /home/dir/of/user/foo | ||
69 | * GLOB_BRACE: | ||
70 | * expand {1,2}{a,b} to 1a 1b 2a 2b | ||
71 | * gl_matchc: | ||
72 | * Number of matches in the current invocation of glob. | ||
73 | */ | ||
74 | |||
75 | |||
76 | #define DOLLAR '$' | ||
77 | #define DOT '.' | ||
78 | #define EOS '\0' | ||
79 | #define LBRACKET '[' | ||
80 | #define NOT '!' | ||
81 | #define QUESTION '?' | ||
82 | #define QUOTE '\\' | ||
83 | #define RANGE '-' | ||
84 | #define RBRACKET ']' | ||
85 | #define SEP '/' | ||
86 | #define STAR '*' | ||
87 | #define TILDE '~' | ||
88 | #define UNDERSCORE '_' | ||
89 | #define LBRACE '{' | ||
90 | #define RBRACE '}' | ||
91 | #define SLASH '/' | ||
92 | #define COMMA ',' | ||
93 | |||
94 | #ifndef DEBUG | ||
95 | |||
96 | #define M_QUOTE 0x8000 | ||
97 | #define M_PROTECT 0x4000 | ||
98 | #define M_MASK 0xffff | ||
99 | #define M_ASCII 0x00ff | ||
100 | |||
101 | typedef u_short Char; | ||
102 | |||
103 | #else | ||
104 | |||
105 | #define M_QUOTE 0x80 | ||
106 | #define M_PROTECT 0x40 | ||
107 | #define M_MASK 0xff | ||
108 | #define M_ASCII 0x7f | ||
109 | |||
110 | typedef char Char; | ||
111 | |||
112 | #endif | ||
113 | |||
114 | |||
115 | #define CHAR(c) ((Char)((c)&M_ASCII)) | ||
116 | #define META(c) ((Char)((c)|M_QUOTE)) | ||
117 | #define M_ALL META('*') | ||
118 | #define M_END META(']') | ||
119 | #define M_NOT META('!') | ||
120 | #define M_ONE META('?') | ||
121 | #define M_RNG META('-') | ||
122 | #define M_SET META('[') | ||
123 | #define ismeta(c) (((c)&M_QUOTE) != 0) | ||
124 | |||
125 | |||
126 | static int compare __P((const void *, const void *)); | ||
127 | static void g_Ctoc __P((const Char *, char *)); | ||
128 | static int g_lstat __P((Char *, struct stat *, glob_t *)); | ||
129 | static DIR *g_opendir __P((Char *, glob_t *)); | ||
130 | static Char *g_strchr __P((Char *, int)); | ||
131 | #ifdef notdef | ||
132 | static Char *g_strcat __P((Char *, const Char *)); | ||
133 | #endif | ||
134 | static int g_stat __P((Char *, struct stat *, glob_t *)); | ||
135 | static int glob0 __P((const Char *, glob_t *)); | ||
136 | static int glob1 __P((Char *, glob_t *)); | ||
137 | static int glob2 __P((Char *, Char *, Char *, glob_t *)); | ||
138 | static int glob3 __P((Char *, Char *, Char *, Char *, glob_t *)); | ||
139 | static int globextend __P((const Char *, glob_t *)); | ||
140 | static const Char * globtilde __P((const Char *, Char *, size_t, glob_t *)); | ||
141 | static int globexp1 __P((const Char *, glob_t *)); | ||
142 | static int globexp2 __P((const Char *, const Char *, glob_t *, int *)); | ||
143 | static int match __P((Char *, Char *, Char *)); | ||
144 | #ifdef DEBUG | ||
145 | static void qprintf __P((const char *, Char *)); | ||
146 | #endif | ||
147 | |||
148 | int | ||
149 | glob(pattern, flags, errfunc, pglob) | ||
150 | const char *pattern; | ||
151 | int flags, (*errfunc) __P((const char *, int)); | ||
152 | glob_t *pglob; | ||
153 | { | ||
154 | const u_char *patnext; | ||
155 | int c; | ||
156 | Char *bufnext, *bufend, patbuf[MAXPATHLEN+1]; | ||
157 | |||
158 | patnext = (u_char *) pattern; | ||
159 | if (!(flags & GLOB_APPEND)) { | ||
160 | pglob->gl_pathc = 0; | ||
161 | pglob->gl_pathv = NULL; | ||
162 | if (!(flags & GLOB_DOOFFS)) | ||
163 | pglob->gl_offs = 0; | ||
164 | } | ||
165 | pglob->gl_flags = flags & ~GLOB_MAGCHAR; | ||
166 | pglob->gl_errfunc = errfunc; | ||
167 | pglob->gl_matchc = 0; | ||
168 | |||
169 | bufnext = patbuf; | ||
170 | bufend = bufnext + MAXPATHLEN; | ||
171 | if (flags & GLOB_NOESCAPE) | ||
172 | while (bufnext < bufend && (c = *patnext++) != EOS) | ||
173 | *bufnext++ = c; | ||
174 | else { | ||
175 | /* Protect the quoted characters. */ | ||
176 | while (bufnext < bufend && (c = *patnext++) != EOS) | ||
177 | if (c == QUOTE) { | ||
178 | if ((c = *patnext++) == EOS) { | ||
179 | c = QUOTE; | ||
180 | --patnext; | ||
181 | } | ||
182 | *bufnext++ = c | M_PROTECT; | ||
183 | } | ||
184 | else | ||
185 | *bufnext++ = c; | ||
186 | } | ||
187 | *bufnext = EOS; | ||
188 | |||
189 | if (flags & GLOB_BRACE) | ||
190 | return globexp1(patbuf, pglob); | ||
191 | else | ||
192 | return glob0(patbuf, pglob); | ||
193 | } | ||
194 | |||
195 | /* | ||
196 | * Expand recursively a glob {} pattern. When there is no more expansion | ||
197 | * invoke the standard globbing routine to glob the rest of the magic | ||
198 | * characters | ||
199 | */ | ||
200 | static int globexp1(pattern, pglob) | ||
201 | const Char *pattern; | ||
202 | glob_t *pglob; | ||
203 | { | ||
204 | const Char* ptr = pattern; | ||
205 | int rv; | ||
206 | |||
207 | /* Protect a single {}, for find(1), like csh */ | ||
208 | if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS) | ||
209 | return glob0(pattern, pglob); | ||
210 | |||
211 | while ((ptr = (const Char *) g_strchr((Char *) ptr, LBRACE)) != NULL) | ||
212 | if (!globexp2(ptr, pattern, pglob, &rv)) | ||
213 | return rv; | ||
214 | |||
215 | return glob0(pattern, pglob); | ||
216 | } | ||
217 | |||
218 | |||
219 | /* | ||
220 | * Recursive brace globbing helper. Tries to expand a single brace. | ||
221 | * If it succeeds then it invokes globexp1 with the new pattern. | ||
222 | * If it fails then it tries to glob the rest of the pattern and returns. | ||
223 | */ | ||
224 | static int globexp2(ptr, pattern, pglob, rv) | ||
225 | const Char *ptr, *pattern; | ||
226 | glob_t *pglob; | ||
227 | int *rv; | ||
228 | { | ||
229 | int i; | ||
230 | Char *lm, *ls; | ||
231 | const Char *pe, *pm, *pl; | ||
232 | Char patbuf[MAXPATHLEN + 1]; | ||
233 | |||
234 | /* copy part up to the brace */ | ||
235 | for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++) | ||
236 | continue; | ||
237 | ls = lm; | ||
238 | |||
239 | /* Find the balanced brace */ | ||
240 | for (i = 0, pe = ++ptr; *pe; pe++) | ||
241 | if (*pe == LBRACKET) { | ||
242 | /* Ignore everything between [] */ | ||
243 | for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++) | ||
244 | continue; | ||
245 | if (*pe == EOS) { | ||
246 | /* | ||
247 | * We could not find a matching RBRACKET. | ||
248 | * Ignore and just look for RBRACE | ||
249 | */ | ||
250 | pe = pm; | ||
251 | } | ||
252 | } | ||
253 | else if (*pe == LBRACE) | ||
254 | i++; | ||
255 | else if (*pe == RBRACE) { | ||
256 | if (i == 0) | ||
257 | break; | ||
258 | i--; | ||
259 | } | ||
260 | |||
261 | /* Non matching braces; just glob the pattern */ | ||
262 | if (i != 0 || *pe == EOS) { | ||
263 | *rv = glob0(patbuf, pglob); | ||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | for (i = 0, pl = pm = ptr; pm <= pe; pm++) | ||
268 | switch (*pm) { | ||
269 | case LBRACKET: | ||
270 | /* Ignore everything between [] */ | ||
271 | for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++) | ||
272 | continue; | ||
273 | if (*pm == EOS) { | ||
274 | /* | ||
275 | * We could not find a matching RBRACKET. | ||
276 | * Ignore and just look for RBRACE | ||
277 | */ | ||
278 | pm = pl; | ||
279 | } | ||
280 | break; | ||
281 | |||
282 | case LBRACE: | ||
283 | i++; | ||
284 | break; | ||
285 | |||
286 | case RBRACE: | ||
287 | if (i) { | ||
288 | i--; | ||
289 | break; | ||
290 | } | ||
291 | /* FALLTHROUGH */ | ||
292 | case COMMA: | ||
293 | if (i && *pm == COMMA) | ||
294 | break; | ||
295 | else { | ||
296 | /* Append the current string */ | ||
297 | for (lm = ls; (pl < pm); *lm++ = *pl++) | ||
298 | continue; | ||
299 | /* | ||
300 | * Append the rest of the pattern after the | ||
301 | * closing brace | ||
302 | */ | ||
303 | for (pl = pe + 1; (*lm++ = *pl++) != EOS;) | ||
304 | continue; | ||
305 | |||
306 | /* Expand the current pattern */ | ||
307 | #ifdef DEBUG | ||
308 | qprintf("globexp2:", patbuf); | ||
309 | #endif | ||
310 | *rv = globexp1(patbuf, pglob); | ||
311 | |||
312 | /* move after the comma, to the next string */ | ||
313 | pl = pm + 1; | ||
314 | } | ||
315 | break; | ||
316 | |||
317 | default: | ||
318 | break; | ||
319 | } | ||
320 | *rv = 0; | ||
321 | return 0; | ||
322 | } | ||
323 | |||
324 | |||
325 | |||
326 | /* | ||
327 | * expand tilde from the passwd file. | ||
328 | */ | ||
329 | static const Char * | ||
330 | globtilde(pattern, patbuf, patbuf_len, pglob) | ||
331 | const Char *pattern; | ||
332 | Char *patbuf; | ||
333 | size_t patbuf_len; | ||
334 | glob_t *pglob; | ||
335 | { | ||
336 | struct passwd *pwd; | ||
337 | char *h; | ||
338 | const Char *p; | ||
339 | Char *b, *eb; | ||
340 | |||
341 | if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE)) | ||
342 | return pattern; | ||
343 | |||
344 | /* Copy up to the end of the string or / */ | ||
345 | eb = &patbuf[patbuf_len - 1]; | ||
346 | for (p = pattern + 1, h = (char *) patbuf; | ||
347 | h < (char *)eb && *p && *p != SLASH; *h++ = *p++) | ||
348 | continue; | ||
349 | |||
350 | *h = EOS; | ||
351 | |||
352 | if (((char *) patbuf)[0] == EOS) { | ||
353 | /* | ||
354 | * handle a plain ~ or ~/ by expanding $HOME | ||
355 | * first and then trying the password file | ||
356 | */ | ||
357 | #if 0 | ||
358 | if (issetugid() != 0 || (h = getenv("HOME")) == NULL) { | ||
359 | #endif | ||
360 | if ((getuid() != geteuid()) || (h = getenv("HOME")) == NULL) { | ||
361 | if ((pwd = getpwuid(getuid())) == NULL) | ||
362 | return pattern; | ||
363 | else | ||
364 | h = pwd->pw_dir; | ||
365 | } | ||
366 | } | ||
367 | else { | ||
368 | /* | ||
369 | * Expand a ~user | ||
370 | */ | ||
371 | if ((pwd = getpwnam((char*) patbuf)) == NULL) | ||
372 | return pattern; | ||
373 | else | ||
374 | h = pwd->pw_dir; | ||
375 | } | ||
376 | |||
377 | /* Copy the home directory */ | ||
378 | for (b = patbuf; b < eb && *h; *b++ = *h++) | ||
379 | continue; | ||
380 | |||
381 | /* Append the rest of the pattern */ | ||
382 | while (b < eb && (*b++ = *p++) != EOS) | ||
383 | continue; | ||
384 | *b = EOS; | ||
385 | |||
386 | return patbuf; | ||
387 | } | ||
388 | |||
389 | |||
390 | /* | ||
391 | * The main glob() routine: compiles the pattern (optionally processing | ||
392 | * quotes), calls glob1() to do the real pattern matching, and finally | ||
393 | * sorts the list (unless unsorted operation is requested). Returns 0 | ||
394 | * if things went well, nonzero if errors occurred. It is not an error | ||
395 | * to find no matches. | ||
396 | */ | ||
397 | static int | ||
398 | glob0(pattern, pglob) | ||
399 | const Char *pattern; | ||
400 | glob_t *pglob; | ||
401 | { | ||
402 | const Char *qpatnext; | ||
403 | int c, err, oldpathc; | ||
404 | Char *bufnext, patbuf[MAXPATHLEN+1]; | ||
405 | |||
406 | qpatnext = globtilde(pattern, patbuf, sizeof(patbuf) / sizeof(Char), | ||
407 | pglob); | ||
408 | oldpathc = pglob->gl_pathc; | ||
409 | bufnext = patbuf; | ||
410 | |||
411 | /* We don't need to check for buffer overflow any more. */ | ||
412 | while ((c = *qpatnext++) != EOS) { | ||
413 | switch (c) { | ||
414 | case LBRACKET: | ||
415 | c = *qpatnext; | ||
416 | if (c == NOT) | ||
417 | ++qpatnext; | ||
418 | if (*qpatnext == EOS || | ||
419 | g_strchr((Char *) qpatnext+1, RBRACKET) == NULL) { | ||
420 | *bufnext++ = LBRACKET; | ||
421 | if (c == NOT) | ||
422 | --qpatnext; | ||
423 | break; | ||
424 | } | ||
425 | *bufnext++ = M_SET; | ||
426 | if (c == NOT) | ||
427 | *bufnext++ = M_NOT; | ||
428 | c = *qpatnext++; | ||
429 | do { | ||
430 | *bufnext++ = CHAR(c); | ||
431 | if (*qpatnext == RANGE && | ||
432 | (c = qpatnext[1]) != RBRACKET) { | ||
433 | *bufnext++ = M_RNG; | ||
434 | *bufnext++ = CHAR(c); | ||
435 | qpatnext += 2; | ||
436 | } | ||
437 | } while ((c = *qpatnext++) != RBRACKET); | ||
438 | pglob->gl_flags |= GLOB_MAGCHAR; | ||
439 | *bufnext++ = M_END; | ||
440 | break; | ||
441 | case QUESTION: | ||
442 | pglob->gl_flags |= GLOB_MAGCHAR; | ||
443 | *bufnext++ = M_ONE; | ||
444 | break; | ||
445 | case STAR: | ||
446 | pglob->gl_flags |= GLOB_MAGCHAR; | ||
447 | /* collapse adjacent stars to one, | ||
448 | * to avoid exponential behavior | ||
449 | */ | ||
450 | if (bufnext == patbuf || bufnext[-1] != M_ALL) | ||
451 | *bufnext++ = M_ALL; | ||
452 | break; | ||
453 | default: | ||
454 | *bufnext++ = CHAR(c); | ||
455 | break; | ||
456 | } | ||
457 | } | ||
458 | *bufnext = EOS; | ||
459 | #ifdef DEBUG | ||
460 | qprintf("glob0:", patbuf); | ||
461 | #endif | ||
462 | |||
463 | if ((err = glob1(patbuf, pglob)) != 0) | ||
464 | return(err); | ||
465 | |||
466 | /* | ||
467 | * If there was no match we are going to append the pattern | ||
468 | * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified | ||
469 | * and the pattern did not contain any magic characters | ||
470 | * GLOB_NOMAGIC is there just for compatibility with csh. | ||
471 | */ | ||
472 | if (pglob->gl_pathc == oldpathc) { | ||
473 | if ((pglob->gl_flags & GLOB_NOCHECK) || | ||
474 | ((pglob->gl_flags & GLOB_NOMAGIC) && | ||
475 | !(pglob->gl_flags & GLOB_MAGCHAR))) | ||
476 | return(globextend(pattern, pglob)); | ||
477 | else | ||
478 | return(GLOB_NOMATCH); | ||
479 | } | ||
480 | if (!(pglob->gl_flags & GLOB_NOSORT)) | ||
481 | qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc, | ||
482 | pglob->gl_pathc - oldpathc, sizeof(char *), compare); | ||
483 | return(0); | ||
484 | } | ||
485 | |||
486 | static int | ||
487 | compare(p, q) | ||
488 | const void *p, *q; | ||
489 | { | ||
490 | return(strcmp(*(char **)p, *(char **)q)); | ||
491 | } | ||
492 | |||
493 | static int | ||
494 | glob1(pattern, pglob) | ||
495 | Char *pattern; | ||
496 | glob_t *pglob; | ||
497 | { | ||
498 | Char pathbuf[MAXPATHLEN+1]; | ||
499 | |||
500 | /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */ | ||
501 | if (*pattern == EOS) | ||
502 | return(0); | ||
503 | return(glob2(pathbuf, pathbuf, pattern, pglob)); | ||
504 | } | ||
505 | |||
506 | /* | ||
507 | * The functions glob2 and glob3 are mutually recursive; there is one level | ||
508 | * of recursion for each segment in the pattern that contains one or more | ||
509 | * meta characters. | ||
510 | */ | ||
511 | static int | ||
512 | glob2(pathbuf, pathend, pattern, pglob) | ||
513 | Char *pathbuf, *pathend, *pattern; | ||
514 | glob_t *pglob; | ||
515 | { | ||
516 | struct stat sb; | ||
517 | Char *p, *q; | ||
518 | int anymeta; | ||
519 | |||
520 | /* | ||
521 | * Loop over pattern segments until end of pattern or until | ||
522 | * segment with meta character found. | ||
523 | */ | ||
524 | for (anymeta = 0;;) { | ||
525 | if (*pattern == EOS) { /* End of pattern? */ | ||
526 | *pathend = EOS; | ||
527 | if (g_lstat(pathbuf, &sb, pglob)) | ||
528 | return(0); | ||
529 | |||
530 | if (((pglob->gl_flags & GLOB_MARK) && | ||
531 | pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) | ||
532 | || (S_ISLNK(sb.st_mode) && | ||
533 | (g_stat(pathbuf, &sb, pglob) == 0) && | ||
534 | S_ISDIR(sb.st_mode)))) { | ||
535 | *pathend++ = SEP; | ||
536 | *pathend = EOS; | ||
537 | } | ||
538 | ++pglob->gl_matchc; | ||
539 | return(globextend(pathbuf, pglob)); | ||
540 | } | ||
541 | |||
542 | /* Find end of next segment, copy tentatively to pathend. */ | ||
543 | q = pathend; | ||
544 | p = pattern; | ||
545 | while (*p != EOS && *p != SEP) { | ||
546 | if (ismeta(*p)) | ||
547 | anymeta = 1; | ||
548 | *q++ = *p++; | ||
549 | } | ||
550 | |||
551 | if (!anymeta) { /* No expansion, do next segment. */ | ||
552 | pathend = q; | ||
553 | pattern = p; | ||
554 | while (*pattern == SEP) | ||
555 | *pathend++ = *pattern++; | ||
556 | } else /* Need expansion, recurse. */ | ||
557 | return(glob3(pathbuf, pathend, pattern, p, pglob)); | ||
558 | } | ||
559 | /* NOTREACHED */ | ||
560 | } | ||
561 | |||
562 | static int | ||
563 | glob3(pathbuf, pathend, pattern, restpattern, pglob) | ||
564 | Char *pathbuf, *pathend, *pattern, *restpattern; | ||
565 | glob_t *pglob; | ||
566 | { | ||
567 | register struct dirent *dp; | ||
568 | DIR *dirp; | ||
569 | int err; | ||
570 | char buf[MAXPATHLEN]; | ||
571 | |||
572 | /* | ||
573 | * The readdirfunc declaration can't be prototyped, because it is | ||
574 | * assigned, below, to two functions which are prototyped in glob.h | ||
575 | * and dirent.h as taking pointers to differently typed opaque | ||
576 | * structures. | ||
577 | */ | ||
578 | struct dirent *(*readdirfunc)(); | ||
579 | |||
580 | *pathend = EOS; | ||
581 | errno = 0; | ||
582 | |||
583 | if ((dirp = g_opendir(pathbuf, pglob)) == NULL) { | ||
584 | /* TODO: don't call for ENOENT or ENOTDIR? */ | ||
585 | if (pglob->gl_errfunc) { | ||
586 | g_Ctoc(pathbuf, buf); | ||
587 | if (pglob->gl_errfunc(buf, errno) || | ||
588 | pglob->gl_flags & GLOB_ERR) | ||
589 | return (GLOB_ABORTED); | ||
590 | } | ||
591 | return(0); | ||
592 | } | ||
593 | |||
594 | err = 0; | ||
595 | |||
596 | /* Search directory for matching names. */ | ||
597 | if (pglob->gl_flags & GLOB_ALTDIRFUNC) | ||
598 | readdirfunc = pglob->gl_readdir; | ||
599 | else | ||
600 | readdirfunc = readdir; | ||
601 | while ((dp = (*readdirfunc)(dirp))) { | ||
602 | register u_char *sc; | ||
603 | register Char *dc; | ||
604 | |||
605 | /* Initial DOT must be matched literally. */ | ||
606 | if (dp->d_name[0] == DOT && *pattern != DOT) | ||
607 | continue; | ||
608 | for (sc = (u_char *) dp->d_name, dc = pathend; | ||
609 | (*dc++ = *sc++) != EOS;) | ||
610 | continue; | ||
611 | if (!match(pathend, pattern, restpattern)) { | ||
612 | *pathend = EOS; | ||
613 | continue; | ||
614 | } | ||
615 | err = glob2(pathbuf, --dc, restpattern, pglob); | ||
616 | if (err) | ||
617 | break; | ||
618 | } | ||
619 | |||
620 | if (pglob->gl_flags & GLOB_ALTDIRFUNC) | ||
621 | (*pglob->gl_closedir)(dirp); | ||
622 | else | ||
623 | closedir(dirp); | ||
624 | return(err); | ||
625 | } | ||
626 | |||
627 | |||
628 | /* | ||
629 | * Extend the gl_pathv member of a glob_t structure to accomodate a new item, | ||
630 | * add the new item, and update gl_pathc. | ||
631 | * | ||
632 | * This assumes the BSD realloc, which only copies the block when its size | ||
633 | * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic | ||
634 | * behavior. | ||
635 | * | ||
636 | * Return 0 if new item added, error code if memory couldn't be allocated. | ||
637 | * | ||
638 | * Invariant of the glob_t structure: | ||
639 | * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and | ||
640 | * gl_pathv points to (gl_offs + gl_pathc + 1) items. | ||
641 | */ | ||
642 | static int | ||
643 | globextend(path, pglob) | ||
644 | const Char *path; | ||
645 | glob_t *pglob; | ||
646 | { | ||
647 | register char **pathv; | ||
648 | register int i; | ||
649 | u_int newsize; | ||
650 | char *copy; | ||
651 | const Char *p; | ||
652 | |||
653 | newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs); | ||
654 | pathv = pglob->gl_pathv ? | ||
655 | realloc((char *)pglob->gl_pathv, newsize) : | ||
656 | malloc(newsize); | ||
657 | if (pathv == NULL) { | ||
658 | if (pglob->gl_pathv) | ||
659 | free(pglob->gl_pathv); | ||
660 | return(GLOB_NOSPACE); | ||
661 | } | ||
662 | |||
663 | if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) { | ||
664 | /* first time around -- clear initial gl_offs items */ | ||
665 | pathv += pglob->gl_offs; | ||
666 | for (i = pglob->gl_offs; --i >= 0; ) | ||
667 | *--pathv = NULL; | ||
668 | } | ||
669 | pglob->gl_pathv = pathv; | ||
670 | |||
671 | for (p = path; *p++;) | ||
672 | continue; | ||
673 | if ((copy = malloc(p - path)) != NULL) { | ||
674 | g_Ctoc(path, copy); | ||
675 | pathv[pglob->gl_offs + pglob->gl_pathc++] = copy; | ||
676 | } | ||
677 | pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; | ||
678 | return(copy == NULL ? GLOB_NOSPACE : 0); | ||
679 | } | ||
680 | |||
681 | |||
682 | /* | ||
683 | * pattern matching function for filenames. Each occurrence of the * | ||
684 | * pattern causes a recursion level. | ||
685 | */ | ||
686 | static int | ||
687 | match(name, pat, patend) | ||
688 | register Char *name, *pat, *patend; | ||
689 | { | ||
690 | int ok, negate_range; | ||
691 | Char c, k; | ||
692 | |||
693 | while (pat < patend) { | ||
694 | c = *pat++; | ||
695 | switch (c & M_MASK) { | ||
696 | case M_ALL: | ||
697 | if (pat == patend) | ||
698 | return(1); | ||
699 | do | ||
700 | if (match(name, pat, patend)) | ||
701 | return(1); | ||
702 | while (*name++ != EOS); | ||
703 | return(0); | ||
704 | case M_ONE: | ||
705 | if (*name++ == EOS) | ||
706 | return(0); | ||
707 | break; | ||
708 | case M_SET: | ||
709 | ok = 0; | ||
710 | if ((k = *name++) == EOS) | ||
711 | return(0); | ||
712 | if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS) | ||
713 | ++pat; | ||
714 | while (((c = *pat++) & M_MASK) != M_END) | ||
715 | if ((*pat & M_MASK) == M_RNG) { | ||
716 | if (c <= k && k <= pat[1]) | ||
717 | ok = 1; | ||
718 | pat += 2; | ||
719 | } else if (c == k) | ||
720 | ok = 1; | ||
721 | if (ok == negate_range) | ||
722 | return(0); | ||
723 | break; | ||
724 | default: | ||
725 | if (*name++ != c) | ||
726 | return(0); | ||
727 | break; | ||
728 | } | ||
729 | } | ||
730 | return(*name == EOS); | ||
731 | } | ||
732 | |||
733 | /* Free allocated data belonging to a glob_t structure. */ | ||
734 | void | ||
735 | globfree(pglob) | ||
736 | glob_t *pglob; | ||
737 | { | ||
738 | register int i; | ||
739 | register char **pp; | ||
740 | |||
741 | if (pglob->gl_pathv != NULL) { | ||
742 | pp = pglob->gl_pathv + pglob->gl_offs; | ||
743 | for (i = pglob->gl_pathc; i--; ++pp) | ||
744 | if (*pp) | ||
745 | free(*pp); | ||
746 | free(pglob->gl_pathv); | ||
747 | } | ||
748 | } | ||
749 | |||
750 | static DIR * | ||
751 | g_opendir(str, pglob) | ||
752 | register Char *str; | ||
753 | glob_t *pglob; | ||
754 | { | ||
755 | char buf[MAXPATHLEN]; | ||
756 | |||
757 | if (!*str) | ||
758 | strcpy(buf, "."); | ||
759 | else | ||
760 | g_Ctoc(str, buf); | ||
761 | |||
762 | if (pglob->gl_flags & GLOB_ALTDIRFUNC) | ||
763 | return((*pglob->gl_opendir)(buf)); | ||
764 | |||
765 | return(opendir(buf)); | ||
766 | } | ||
767 | |||
768 | static int | ||
769 | g_lstat(fn, sb, pglob) | ||
770 | register Char *fn; | ||
771 | struct stat *sb; | ||
772 | glob_t *pglob; | ||
773 | { | ||
774 | char buf[MAXPATHLEN]; | ||
775 | |||
776 | g_Ctoc(fn, buf); | ||
777 | if (pglob->gl_flags & GLOB_ALTDIRFUNC) | ||
778 | return((*pglob->gl_lstat)(buf, sb)); | ||
779 | return(lstat(buf, sb)); | ||
780 | } | ||
781 | |||
782 | static int | ||
783 | g_stat(fn, sb, pglob) | ||
784 | register Char *fn; | ||
785 | struct stat *sb; | ||
786 | glob_t *pglob; | ||
787 | { | ||
788 | char buf[MAXPATHLEN]; | ||
789 | |||
790 | g_Ctoc(fn, buf); | ||
791 | if (pglob->gl_flags & GLOB_ALTDIRFUNC) | ||
792 | return((*pglob->gl_stat)(buf, sb)); | ||
793 | return(stat(buf, sb)); | ||
794 | } | ||
795 | |||
796 | static Char * | ||
797 | g_strchr(str, ch) | ||
798 | Char *str; | ||
799 | int ch; | ||
800 | { | ||
801 | do { | ||
802 | if (*str == ch) | ||
803 | return (str); | ||
804 | } while (*str++); | ||
805 | return (NULL); | ||
806 | } | ||
807 | |||
808 | #ifdef notdef | ||
809 | static Char * | ||
810 | g_strcat(dst, src) | ||
811 | Char *dst; | ||
812 | const Char* src; | ||
813 | { | ||
814 | Char *sdst = dst; | ||
815 | |||
816 | while (*dst++) | ||
817 | continue; | ||
818 | --dst; | ||
819 | while((*dst++ = *src++) != EOS) | ||
820 | continue; | ||
821 | |||
822 | return (sdst); | ||
823 | } | ||
824 | #endif | ||
825 | |||
826 | static void | ||
827 | g_Ctoc(str, buf) | ||
828 | register const Char *str; | ||
829 | char *buf; | ||
830 | { | ||
831 | register char *dc; | ||
832 | |||
833 | for (dc = buf; (*dc++ = *str++) != EOS;) | ||
834 | continue; | ||
835 | } | ||
836 | |||
837 | #ifdef DEBUG | ||
838 | static void | ||
839 | qprintf(str, s) | ||
840 | const char *str; | ||
841 | register Char *s; | ||
842 | { | ||
843 | register Char *p; | ||
844 | |||
845 | (void)printf("%s:\n", str); | ||
846 | for (p = s; *p; p++) | ||
847 | (void)printf("%c", CHAR(*p)); | ||
848 | (void)printf("\n"); | ||
849 | for (p = s; *p; p++) | ||
850 | (void)printf("%c", *p & M_PROTECT ? '"' : ' '); | ||
851 | (void)printf("\n"); | ||
852 | for (p = s; *p; p++) | ||
853 | (void)printf("%c", ismeta(*p) ? '_' : ' '); | ||
854 | (void)printf("\n"); | ||
855 | } | ||
856 | #endif | ||
857 | |||
858 | #endif /* !defined(HAVE_GLOB) || !defined(GLOB_HAS_ALTDIRFUNC) */ | ||
859 | |||