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