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