* Copyright (c) 1989 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* %sccs.include.redist.c%
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid
[] = "@(#)glob.c 5.3 (Berkeley) %G%";
#endif /* LIBC_SCCS and not lint */
* Glob: the interface is a superset of the one defined in POSIX 1003.2,
* The [!...] convention to negate a range is supported (SysV, Posix, ksh).
* Optional extra services, controlled by flags not defined by POSIX:
* GLOB_QUOTE: escaping convention: \ inhibits any special meaning
the following character might have (except \ at end of
char *malloc(), *realloc();
#define META(c) ((c)|METABIT)
#define ismeta(c) (((c)&METABIT) != 0)
return(strcmp(*(char **)p
, *(char **)q
));
* The main glob() routine: compiles the pattern (optionally processing
* quotes), calls glob1() to do the real pattern matching, and finally
* sorts the list (unless unsorted operation is requested). Returns 0
* if things went well, nonzero if errors occurred. It is not an error
glob(pattern
, flags
, errfunc
, pglob
)
char *bufnext
, *bufend
, *compilebuf
, *compilepat
, *patnext
;
char c
, patbuf
[MAXPATHLEN
+1];
if (!(flags
& GLOB_APPEND
)) {
if (!(flags
& GLOB_DOOFFS
))
pglob
->gl_errfunc
= errfunc
;
oldpathc
= pglob
->gl_pathc
;
bufend
= bufnext
+MAXPATHLEN
;
while (bufnext
< bufend
&& (c
= *patnext
++) != EOS
) {
strchr(patnext
+1, RBRACKET
) == NULL
) {
(c
= patnext
[1]) != RBRACKET
) {
} while ((c
= *patnext
++) != RBRACKET
);
if (!(flags
& GLOB_QUOTE
))
if ((c
= *patnext
++) == EOS
) {
if ((err
= glob1(patbuf
, pglob
)) != 0)
if (pglob
->gl_pathc
== oldpathc
&& flags
& GLOB_NOCHECK
) {
if (!(flags
& GLOB_QUOTE
))
(void)strcpy(compilebuf
, compilepat
);
* copy pattern, interpreting quotes; this is slightly
* different than the interpretation of quotes above
* -- which should prevail?
while (*compilepat
!= EOS
) {
if (*compilepat
== QUOTE
) {
if (*++compilepat
== EOS
)
*compilebuf
++ = *compilepat
++;
return(globextend(patbuf
, pglob
));
} else if (!(flags
& GLOB_NOSORT
))
qsort((char*) (pglob
->gl_pathv
+ pglob
->gl_offs
+ oldpathc
),
pglob
->gl_pathc
- oldpathc
, sizeof(char*), compare
);
char pathbuf
[MAXPATHLEN
+1];
* a null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
return(glob2(pathbuf
, pathbuf
, pattern
, pglob
));
* functions glob2 and glob3 are mutually recursive; there is one level
* of recursion for each segment in the pattern that contains one or
glob2(pathbuf
, pathend
, pattern
, pglob
)
char *pathbuf
, *pathend
, *pattern
;
* loop over pattern segments until end of pattern or until
* segment with meta character found.
if (*pattern
== EOS
) { /* end of pattern? */
if (stat(pathbuf
, &sbuf
) != 0)
return(0); /* need error call here? */
if ((pglob
->gl_flags
& GLOB_MARK
) &&
pathend
[-1] != SEP
&& S_ISDIR(sbuf
.st_mode
)) {
return(globextend(pathbuf
, pglob
));
/* find end of next segment, copy tentatively to pathend */
while (*p
!= EOS
&& *p
!= SEP
) {
if (!anymeta
) { /* no expansion, do next segment */
} else /* need expansion, recurse */
return(glob3(pathbuf
, pathend
, pattern
, p
, pglob
));
glob3(pathbuf
, pathend
, pattern
, restpattern
, pglob
)
char *pathbuf
, *pathend
, *pattern
, *restpattern
;
if (!(dirp
= opendir(pathbuf
)))
/* todo: don't call for ENOENT or ENOTDIR? */
(*pglob
->gl_errfunc
)(pathbuf
, errno
) ||
(pglob
->gl_flags
& GLOB_ERR
))
/* search directory for matching names */
while ((dp
= readdir(dirp
))) {
/* initial DOT must be matched literally */
if (dp
->d_name
[0] == DOT
&& *pattern
!= DOT
)
if (!match(dp
->d_name
, pattern
, restpattern
))
(void)strcpy(pathend
, dp
->d_name
);
err
= glob2(pathbuf
, pathend
+len
, restpattern
, pglob
);
/* todo: check error from readdir? */
* Extend the gl_pathv member of a glob_t structure to accomodate a new item,
* add the new item, and update gl_pathc.
* This assumes the BSD realloc, which only copies the block when its size
* crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
* Return 0 if new item added, error code if memory couldn't be allocated.
* Invariant of the glob_t structure:
* Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
* gl_pathv points to (gl_offs + gl_pathc + 1) items.
newsize
= sizeof(*pathv
) * (2 + pglob
->gl_pathc
+ pglob
->gl_offs
);
pathv
= (char **)realloc((char *)(pathv
= pglob
->gl_pathv
), newsize
);
if (pglob
->gl_pathv
== NULL
&& pglob
->gl_offs
> 0) {
/* first time around -- clear initial gl_offs items */
for (i
= pglob
->gl_offs
; --i
>= 0; )
copysize
= strlen(path
) + 1;
if ((copy
= malloc(copysize
)) != NULL
) {
(void)strcpy(copy
, path
);
pathv
[pglob
->gl_offs
+ pglob
->gl_pathc
++] = copy
;
pathv
[pglob
->gl_offs
+ pglob
->gl_pathc
] = NULL
;
return((copy
== NULL
) ? GLOB_NOSPACE
: 0);
* pattern matching function for filenames. Each occurrence of the *
* pattern causes a recursion level.
register char *name
, *pat
, *patend
;
for (; *name
!= EOS
; ++name
) {
if (match(name
, pat
, patend
))
if (negate_range
= (*pat
& 0xff) == M_NOT
)
while (((c
= *pat
++) & 0xff) != M_END
) {
if ((*pat
& 0xff) == M_RNG
) {
if (c
<= k
&& k
<= pat
[1])
/* free allocated data belonging to a glob_t structure */
if (pglob
->gl_pathv
!= NULL
) {
pp
= pglob
->gl_pathv
+ pglob
->gl_offs
;
for (i
= pglob
->gl_pathc
; i
--; ++pp
)