18 static int is_literal(const char *p
, int useesc
)
32 if (bracket
) return 0;
39 static int append(struct match
**tail
, const char *name
, size_t len
, int mark
)
41 struct match
*new = malloc(sizeof(struct match
) + len
+ 1);
45 strcpy(new->name
, name
);
46 if (mark
) strcat(new->name
, "/");
51 static int match_in_dir(const char *d
, const char *p
, int flags
, int (*errfunc
)(const char *path
, int err
), struct match
**tail
)
54 struct dirent de_buf
, *de
;
55 char pat
[strlen(p
)+1];
59 int fnm_flags
= ((flags
& GLOB_NOESCAPE
) ? FNM_NOESCAPE
: 0)
60 | ((!(flags
& GLOB_PERIOD
)) ? FNM_PERIOD
: 0);
63 if ((p2
= strchr(p
, '/'))) {
66 for (; *p2
== '/'; p2
++);
69 literal
= is_literal(p
, !(flags
& GLOB_NOESCAPE
));
70 if (*d
== '/' && !*(d
+1)) l
= 0;
72 /* rely on opendir failing for nondirectory objects */
73 dir
= opendir(*d
? d
: ".");
76 /* this is not an error -- we let opendir call stat for us */
77 if (error
== ENOTDIR
) return 0;
78 if (error
== EACCES
&& !*p
) {
80 if (!stat(d
, &st
) && S_ISDIR(st
.st_mode
)) {
81 if (append(tail
, d
, l
, l
))
86 if (errfunc(d
, error
) || (flags
& GLOB_ERR
))
91 error
= append(tail
, d
, l
, l
) ? GLOB_NOSPACE
: 0;
95 while (!(error
= readdir_r(dir
, &de_buf
, &de
)) && de
) {
96 char namebuf
[l
+de
->d_reclen
+2], *name
= namebuf
;
97 if (!literal
&& fnmatch(p
, de
->d_name
, fnm_flags
))
99 if (literal
&& strcmp(p
, de
->d_name
))
101 if (p2
&& de
->d_type
&& !S_ISDIR(de
->d_type
<<12) && !S_ISLNK(de
->d_type
<<12))
106 strcpy(name
+l
+1, de
->d_name
);
111 if ((error
= match_in_dir(name
, p2
, flags
, errfunc
, tail
))) {
117 if (flags
& GLOB_MARK
) {
118 if (de
->d_type
&& !S_ISLNK(de
->d_type
<<12))
119 mark
= S_ISDIR(de
->d_type
<<12);
123 mark
= S_ISDIR(st
.st_mode
);
126 if (append(tail
, name
, l
+de
->d_reclen
+1, mark
)) {
133 if (error
&& (errfunc(d
, error
) || (flags
& GLOB_ERR
)))
138 static int ignore_err(const char *path
, int err
)
143 static void freelist(struct match
*head
)
145 struct match
*match
, *next
;
146 for (match
=head
->next
; match
; match
=next
) {
152 static int sort(const void *a
, const void *b
)
154 return strcmp(*(const char **)a
, *(const char **)b
);
157 int glob(const char *restrict pat
, int flags
, int (*errfunc
)(const char *path
, int err
), glob_t
*restrict g
)
159 const char *p
=pat
, *d
;
160 struct match head
= { .next
= NULL
}, *tail
= &head
;
162 size_t offs
= (flags
& GLOB_DOOFFS
) ? g
->gl_offs
: 0;
166 for (; *p
== '/'; p
++);
172 if (strlen(p
) > PATH_MAX
) return GLOB_NOSPACE
;
174 if (!errfunc
) errfunc
= ignore_err
;
176 if (!(flags
& GLOB_APPEND
)) {
182 if (*p
) error
= match_in_dir(d
, p
, flags
, errfunc
, &tail
);
183 if (error
== GLOB_NOSPACE
) {
188 for (cnt
=0, tail
=head
.next
; tail
; tail
=tail
->next
, cnt
++);
190 if (flags
& GLOB_NOCHECK
) {
192 if (append(&tail
, pat
, strlen(pat
), 0))
199 if (flags
& GLOB_APPEND
) {
200 char **pathv
= realloc(g
->gl_pathv
, (offs
+ g
->gl_pathc
+ cnt
+ 1) * sizeof(char *));
208 g
->gl_pathv
= malloc((offs
+ cnt
+ 1) * sizeof(char *));
213 for (i
=0; i
<offs
; i
++)
214 g
->gl_pathv
[i
] = NULL
;
216 for (i
=0, tail
=head
.next
; i
<cnt
; tail
=tail
->next
, i
++)
217 g
->gl_pathv
[offs
+ i
] = tail
->name
;
218 g
->gl_pathv
[offs
+ i
] = NULL
;
221 if (!(flags
& GLOB_NOSORT
))
222 qsort(g
->gl_pathv
+offs
, cnt
, sizeof(char *), sort
);
227 void globfree(glob_t
*g
)
230 for (i
=0; i
<g
->gl_pathc
; i
++)
231 free(g
->gl_pathv
[g
->gl_offs
+ i
] - offsetof(struct match
, name
));