30# if defined(HAVE_FDOPENDIR) && defined(HAVE_DIRFD) && \
31 defined(HAVE_OPENAT) && defined(HAVE_FSTATAT)
32# define USE_OPENDIR_AT 1
34# define USE_OPENDIR_AT 0
42#undef HAVE_DIRENT_NAMLEN
43#if defined HAVE_DIRENT_H && !defined _WIN32
45# define NAMLEN(dirent) strlen((dirent)->d_name)
46#elif defined HAVE_DIRECT_H && !defined _WIN32
48# define NAMLEN(dirent) strlen((dirent)->d_name)
51# define NAMLEN(dirent) (dirent)->d_namlen
52# define HAVE_DIRENT_NAMLEN 1
79#define USE_NAME_ON_FS_REAL_BASENAME 1
81#define USE_NAME_ON_FS_BY_FNMATCH 2
84#ifdef HAVE_GETATTRLIST
85# define USE_NAME_ON_FS USE_NAME_ON_FS_REAL_BASENAME
86# define RUP32(size) ((size)+3/4)
87# define SIZEUP32(type) RUP32(sizeof(type))
89# define USE_NAME_ON_FS USE_NAME_ON_FS_REAL_BASENAME
91# define USE_NAME_ON_FS USE_NAME_ON_FS_BY_FNMATCH
93# define USE_NAME_ON_FS 0
97# define NORMALIZE_UTF8PATH 1
98# include <sys/param.h>
99# include <sys/mount.h>
100# include <sys/vnode.h>
102# define NORMALIZE_UTF8PATH 0
111#include "internal/error.h"
113#include "internal/gc.h"
126#define vm_initialized rb_cThread
131# define chdir(p) rb_w32_uchdir(p)
133# define mkdir(p, m) rb_w32_umkdir((p), (m))
135# define rmdir(p) rb_w32_urmdir(p)
137# define opendir(p) rb_w32_uopendir(p)
138# define ruby_getcwd() rb_w32_ugetcwd(NULL, 0)
144#if NORMALIZE_UTF8PATH
145# if defined HAVE_FGETATTRLIST || !defined HAVE_GETATTRLIST
146# define need_normalization(dirp, path) need_normalization(dirp)
148# define need_normalization(dirp, path) need_normalization(path)
151need_normalization(
DIR *dirp,
const char *path)
153# if defined HAVE_FGETATTRLIST || defined HAVE_GETATTRLIST
154 u_int32_t attrbuf[SIZEUP32(fsobj_tag_t)];
155 struct attrlist al = {ATTR_BIT_MAP_COUNT, 0, ATTR_CMN_OBJTAG,};
156# if defined HAVE_FGETATTRLIST
157 int ret = fgetattrlist(dirfd(dirp), &al, attrbuf,
sizeof(attrbuf), 0);
159 int ret = getattrlist(path, &al, attrbuf,
sizeof(attrbuf), 0);
162 const fsobj_tag_t *tag = (
void *)(attrbuf+1);
174has_nonascii(
const char *
ptr,
size_t len)
184# define IF_NORMALIZE_UTF8PATH(something) something
186# define IF_NORMALIZE_UTF8PATH(something)
190# define IFTODT(m) (((m) & S_IFMT) / ((~S_IFMT & (S_IFMT-1)) + 1))
209#define FNM_NOESCAPE 0x01
210#define FNM_PATHNAME 0x02
211#define FNM_DOTMATCH 0x04
212#define FNM_CASEFOLD 0x08
213#define FNM_EXTGLOB 0x10
214#if CASEFOLD_FILESYSTEM
215#define FNM_SYSCASE FNM_CASEFOLD
220#define FNM_SHORTNAME 0x20
222#define FNM_SHORTNAME 0
224#define FNM_GLOB_NOSORT 0x40
229# define Next(p, e, enc) ((p)+ rb_enc_mbclen((p), (e), (enc)))
230# define Inc(p, e, enc) ((p) = Next((p), (e), (enc)))
247 if (p >= pend)
return NULL;
248 if (*p ==
'!' || *p ==
'^') {
255 if (escape && *t1 ==
'\\')
260 if (p >= pend)
return NULL;
261 if (p[0] ==
'-' && p[1] !=
']') {
262 const char *t2 = p + 1;
264 if (escape && *t2 ==
'\\')
270 if ((r <= (send-s) &&
memcmp(t1, s, r) == 0) ||
279 if (c1 < c2)
continue;
282 if (c1 > c2)
continue;
286 if (r <= (send-s) &&
memcmp(t1, s, r) == 0) {
290 if (!nocase)
continue;
293 if (c1 != c2)
continue;
298 return ok == not ?
NULL : (
char *)p + 1;
306#define UNESCAPE(p) (escape && *(p) == '\\' ? (p) + 1 : (p))
307#define ISEND(p) (!*(p) || (pathname && *(p) == '/'))
308#define RETURN(val) return *pcur = p, *scur = s, (val);
322 const char *ptmp = 0;
323 const char *stmp = 0;
325 const char *p = *pcur;
326 const char *pend = p +
strlen(p);
327 const char *s = *scur;
328 const char *send = s +
strlen(s);
332 if (period && *s ==
'.' && *
UNESCAPE(p) !=
'.')
338 do { p++; }
while (*p ==
'*');
360 if ((
t = bracket(p + 1, pend, s, send, flags, enc)) != 0) {
378 if (r <= (send-s) &&
memcmp(p, s, r) == 0) {
383 if (!nocase)
goto failed;
394 Inc(stmp, send, enc);
409 const char *p = pattern;
410 const char *s = string;
411 const char *send = s +
strlen(
string);
415 const char *ptmp = 0;
416 const char *stmp = 0;
420 if (p[0] ==
'*' && p[1] ==
'*' && p[2] ==
'/') {
421 do { p += 3; }
while (p[0] ==
'*' && p[1] ==
'*' && p[2] ==
'/');
425 if (fnmatch_helper(&p, &s, flags, enc) == 0) {
426 while (*s && *s !=
'/')
Inc(s, send, enc);
436 if (ptmp && stmp && !(period && *stmp ==
'.')) {
437 while (*stmp && *stmp !=
'/')
Inc(stmp, send, enc);
449 return fnmatch_helper(&p, &s, flags, enc);
477dir_memsize(
const void *
ptr)
484 {dir_mark, dir_free, dir_memsize,},
491dir_s_alloc(
VALUE klass)
504nogvl_opendir(
void *
ptr)
512opendir_without_gvl(
const char *
path)
515 union {
const void *
in;
void *
out; } u;
544 dp->dir = opendir_without_gvl(
path);
548 dp->dir = opendir_without_gvl(
path);
550#ifdef HAVE_GETATTRLIST
552 u_int32_t attrbuf[1];
553 struct attrlist al = {ATTR_BIT_MAP_COUNT, 0};
554 if (getattrlist(path, &al, attrbuf,
sizeof(attrbuf), FSOPT_NOFOLLOW) == 0) {
555 dp->dir = opendir_without_gvl(path);
575 dir_initialize(ec,
dir, dirname,
enc);
583 return dir_close(
dir);
586NORETURN(
static void dir_closed(
void));
605 if (!dirp->
dir) dir_closed();
609#define GetDIR(obj, dirp) ((dirp) = dir_check(obj))
638#if defined(__sun) && !defined(HAVE_DIRFD)
639# if defined(HAVE_DIR_D_FD)
640# define dirfd(x) ((x)->d_fd)
642# elif defined(HAVE_DIR_DD_FD)
643# define dirfd(x) ((x)->dd_fd)
670 fd = dirfd(dirp->
dir);
676#define dir_fileno rb_f_notimplement
712# define READDIR(dir, enc) rb_w32_readdir((dir), (enc))
714# define READDIR(dir, enc) readdir((dir))
719to_be_skipped(
const struct dirent *
dp)
721 const char *
name =
dp->d_name;
723#ifdef HAVE_DIRENT_NAMLEN
802 return dir_each_entry(dir, dir_yield,
Qnil,
FALSE);
816 const char *
name =
dp->d_name;
820 if (children_only &&
name[0] ==
'.') {
821 if (namlen == 1)
continue;
822 if (namlen == 2 &&
name[1] ==
'.')
continue;
824#if NORMALIZE_UTF8PATH
825 if (norm_p && has_nonascii(
name, namlen) &&
826 !
NIL_P(path = rb_str_normalize_ospath(
name, namlen))) {
861#define dir_tell rb_f_notimplement
890#define dir_seek rb_f_notimplement
914#define dir_set_pos rb_f_notimplement
962nogvl_chdir(
void *
ptr)
976static int chdir_blocking = 0;
991 if (chdir_thread ==
Qnil)
997chdir_restore(
VALUE v)
1002 if (chdir_blocking == 0)
1003 chdir_thread =
Qnil;
1058 const char *dist =
getenv(
"HOME");
1066 if (chdir_blocking > 0) {
1070 rb_warn(
"conflicting chdir during another chdir block");
1100#undef RUBY_UNTYPED_DATA_WARNING
1101#define RUBY_UNTYPED_DATA_WARNING 0
1106 cwd = rb_str_normalize_ospath(path,
strlen(path));
1129#if defined _WIN32 || defined __APPLE__
1150dir_s_getwd(
VALUE dir)
1156check_dirname(
VALUE dir)
1168 if (pend - path <
len) {
1175#if defined(HAVE_CHROOT)
1188 path = check_dirname(path);
1195#define dir_s_chroot rb_f_notimplement
1204nogvl_mkdir(
void *
ptr)
1249nogvl_rmdir(
void *
ptr)
1271 dir = check_dirname(dir);
1281#ifdef RUBY_FUNCTION_NAME_STRING
1288#ifndef RUBY_FUNCTION_NAME_STRING
1289#define sys_enc_warning_in(func, mesg, enc) sys_enc_warning(mesg, enc)
1293sys_warning_1(
VALUE mesg)
1296#ifdef RUBY_FUNCTION_NAME_STRING
1308#ifdef RUBY_FUNCTION_NAME_STRING
1316#define GLOB_VERBOSE (1U << (sizeof(int) * CHAR_BIT - 1))
1317#define sys_warning(val, enc) \
1318 ((flags & GLOB_VERBOSE) ? sys_enc_warning_in(RUBY_FUNCTION_NAME_STRING, (val), (enc)) :(void)0)
1321glob_alloc_size(
size_t x,
size_t y)
1324 if (rb_mul_size_overflow(x, y,
SSIZE_MAX, &z)) {
1333glob_alloc_n(
size_t x,
size_t y)
1335 return malloc(glob_alloc_size(x, y));
1339glob_realloc_n(
void *p,
size_t x,
size_t y)
1341 return realloc(p, glob_alloc_size(x, y));
1344#define GLOB_ALLOC(type) ((type *)malloc(sizeof(type)))
1345#define GLOB_ALLOC_N(type, n) ((type *)glob_alloc_n(sizeof(type), n))
1346#define GLOB_REALLOC(ptr, size) realloc((ptr), (size))
1347#define GLOB_REALLOC_N(ptr, n) glob_realloc_n(ptr, sizeof(*(ptr)), n)
1348#define GLOB_FREE(ptr) free(ptr)
1349#define GLOB_JUMP_TAG(status) (((status) == -1) ? rb_memerror() : rb_jump_tag(status))
1359 return e == ENOENT || e == ENOTDIR;
1363#define STAT(p, s) rb_w32_ustati128((p), (s))
1365#define lstat(p, s) rb_w32_ulstati128((p), (s))
1367#define STAT(p, s) stat((p), (s))
1377at_subpath(
int fd,
size_t baselen,
const char *path)
1380 if (fd != (
int)
AT_FDCWD && baselen > 0) {
1382 if (*path ==
'/') ++path;
1385 return *path ? path :
".";
1390do_stat(
int fd,
size_t baselen,
const char *path,
struct stat *pst,
int flags,
rb_encoding *enc)
1393 int ret = fstatat(fd, at_subpath(fd, baselen, path), pst, 0);
1395 int ret =
STAT(path, pst);
1397 if (ret < 0 && !to_be_ignored(errno))
1403#if defined HAVE_LSTAT || defined lstat || USE_OPENDIR_AT
1408 int ret = fstatat(fd, at_subpath(fd, baselen, path), pst, AT_SYMLINK_NOFOLLOW);
1410 int ret =
lstat(path, pst);
1412 if (ret < 0 && !to_be_ignored(errno))
1418#define do_lstat do_stat
1427with_gvl_gc_for_fd(
void *
ptr)
1435gc_for_fd_with_gvl(
int e)
1444nogvl_opendir_at(
void *
ptr)
1450 const int opendir_flags = (O_RDONLY|
O_CLOEXEC|
1455 int fd = openat(oaa->
basefd, oaa->
path, opendir_flags);
1457 dirp = fd >= 0 ? fdopendir(fd) : 0;
1461 switch (gc_for_fd_with_gvl(e)) {
1463 if (fd < 0) fd = openat(oaa->
basefd, oaa->
path, opendir_flags);
1464 if (fd >= 0) dirp = fdopendir(fd);
1465 if (dirp)
return dirp;
1470 if (fd >= 0) close(fd);
1476 if (!dirp && gc_for_fd_with_gvl(errno))
1494 return nogvl_opendir_at(&oaa);
1504 if (!fundamental_encoding_p(enc)) {
1515 if (!to_be_ignored(e)) {
1517 *status = (*errfunc)(
path, arg, enc, e);
1536has_magic(
const char *p,
const char *pend,
int flags,
rb_encoding *enc)
1544 while (p < pend && (c = *p++) != 0) {
1556 if (escape && p++ >= pend)
1575 p =
Next(p-1, pend, enc);
1583find_dirsep(
const char *p,
const char *pend,
int flags,
rb_encoding *enc)
1590 while ((c = *p++) != 0) {
1612 if (escape && !(c = *p++))
1617 p =
Next(p-1, pend, enc);
1625remove_backslashes(
char *p,
register const char *pend,
rb_encoding *enc)
1655static void glob_free_pattern(
struct glob_pattern *list);
1658glob_make_pattern(
const char *p,
const char *e,
int flags,
rb_encoding *enc)
1664 while (p < e && *p) {
1666 if (!tmp)
goto error;
1667 if (p + 2 < e && p[0] ==
'*' && p[1] ==
'*' && p[2] ==
'/') {
1669 do { p += 3;
while (*p ==
'/') p++; }
while (p[0] ==
'*' && p[1] ==
'*' && p[2] ==
'/');
1676 const char *m = find_dirsep(p, e, flags, enc);
1681 if (!(
FNM_SYSCASE || magic > non_magic) && !recursive && *m) {
1683 while (has_magic(m+1, m2 = find_dirsep(m+1, e, flags, enc), flags, enc) <= non_magic &&
1723 glob_free_pattern(list);
1740join_path(
const char *path,
size_t len,
int dirsep,
const char *
name,
size_t namlen)
1754#ifdef HAVE_GETATTRLIST
1755# if defined HAVE_FGETATTRLIST
1756# define is_case_sensitive(dirp, path) is_case_sensitive(dirp)
1758# define is_case_sensitive(dirp, path) is_case_sensitive(path)
1761is_case_sensitive(
DIR *dirp,
const char *path)
1765 vol_capabilities_attr_t cap[1];
1767 struct attrlist al = {ATTR_BIT_MAP_COUNT, 0, 0, ATTR_VOL_INFO|ATTR_VOL_CAPABILITIES};
1768 const vol_capabilities_attr_t *
const cap = attrbuf[0].cap;
1769 const int idx = VOL_CAPABILITIES_FORMAT;
1772# if defined HAVE_FGETATTRLIST
1773 if (fgetattrlist(dirfd(dirp), &al, attrbuf,
sizeof(attrbuf), FSOPT_NOFOLLOW))
1776 if (getattrlist(path, &al, attrbuf,
sizeof(attrbuf), FSOPT_NOFOLLOW))
1779 if (!(cap->valid[idx] &
mask))
1781 return (cap->capabilities[idx] &
mask) != 0;
1789 attrreference_t ref[1];
1790 fsobj_type_t objtype;
1793 struct attrlist al = {ATTR_BIT_MAP_COUNT, 0, ATTR_CMN_NAME|ATTR_CMN_OBJTYPE};
1794 const attrreference_t *
const ar = attrbuf[0].ref;
1801 if (getattrlist(path, &al, attrbuf,
sizeof(attrbuf), FSOPT_NOFOLLOW)) {
1802 if (!to_be_ignored(errno))
1807 switch (attrbuf[0].objtype) {
1813 name = (
char *)ar + ar->attr_dataoffset;
1814 len = (
long)ar->attr_length - 1;
1815 if (
name +
len > (
char *)attrbuf +
sizeof(attrbuf))
1818# if NORMALIZE_UTF8PATH
1819 if (norm_p && has_nonascii(
name,
len)) {
1820 if (!
NIL_P(utf8str = rb_str_normalize_ospath(
name,
len))) {
1830 path[base +
len] =
'\0';
1842 char *plainname = path;
1843 volatile VALUE tmp = 0;
1844 WIN32_FIND_DATAW fd;
1845 WIN32_FILE_ATTRIBUTE_DATA fa;
1850 if (!fundamental_encoding_p(enc)) {
1857 if (!wplain)
return path;
1858 if (GetFileAttributesExW(wplain, GetFileExInfoStandard, &fa)) {
1859 h = FindFirstFileW(wplain, &fd);
1862 if (fa.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
1864 fa.dwFileAttributes &= ~FILE_ATTRIBUTE_REPARSE_POINT;
1869 if (e && !to_be_ignored(e)) {
1877 (fa.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ?
path_symlink :
1878 (fa.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
path_directory :
1888 path[base + wlen] = 0;
1894 wlen = WideCharToMultiByte(CP_UTF8, 0, fd.cFileName, -1,
NULL, 0,
NULL,
NULL);
1898 WideCharToMultiByte(CP_UTF8, 0, fd.cFileName, -1, utf8filename, wlen,
NULL,
NULL);
1902 memcpy(path + base, utf8filename, wlen);
1903 path[base + wlen] = 0;
1910#elif USE_NAME_ON_FS == USE_NAME_ON_FS_REAL_BASENAME
1911# error not implemented
1915# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
1920# define S_ISLNK(m) (0)
1922# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
1935#define glob_call_func(func, path, arg, enc) (*(func))((path), (arg), (void *)(enc))
1938glob_func_caller(
VALUE val)
1953glob_func_warning(
VALUE val)
1978glob_func_error(
VALUE val)
1993 if (
error == EACCES) {
1994 errfunc = glob_func_warning;
2007 const char *d_altname;
2015 if (fnmatch(pat, enc,
name, flags) == 0)
return 1;
2018 if (fnmatch(pat, enc,
dp->d_altname, flags) == 0)
return 1;
2043dirent_match_brace(
const char *pattern,
VALUE val,
void *enc)
2047 return dirent_match(pattern, enc, arg->
name, arg->
dp, arg->
flags);
2056 size_t path_len = 0;
2058 for (p = *beg; p; p = p->
next) {
2077 path[path_len] =
'\0';
2086 path[path_len++] =
'/';
2089 path[path_len] =
'\0';
2096static int push_caller(
const char *path,
VALUE val,
void *enc);
2101static const size_t rb_dirent_name_offset =
2109 const size_t altlen =
2111 dp->d_altlen ?
dp->d_altlen + 1 :
2115 if (!rdp && !(newrdp =
malloc(rb_dirent_name_offset + namlen + 1 + altlen)))
2119 char *
name = (
char *)newrdp + rb_dirent_name_offset;
2121 name[namlen] =
'\0';
2123 newrdp->d_altname =
NULL;
2125 char *
const altname =
name + namlen + 1;
2126 memcpy(altname,
dp->d_altname, altlen - 1);
2127 altname[altlen - 1] =
'\0';
2128 newrdp->d_altname = altname;
2136 newrdp->d_altname =
dp->d_altname;
2159glob_sort_cmp(
const void *a,
const void *b,
void *e)
2194 size_t count = 0, capacity = 0;
2199 if ((capacity = dirp->
nfiles) > 0) {
2212 if (
count >= capacity) {
2222 if (
count < capacity) {
2224 glob_dir_finish(ent, 0);
2230 glob_sort_cmp,
NULL);
2235 glob_dir_finish(ent, 0);
2272 int plain = 0, brace = 0, magical = 0, recursive = 0, match_all = 0, match_dir = 0;
2274 size_t pathlen = baselen + namelen;
2278 for (cur = beg; cur < end; ++cur) {
2289#if USE_NAME_ON_FS == USE_NAME_ON_FS_REAL_BASENAME
2310 rb_bug(
"continuous RECURSIVEs");
2316 char* brace_path = join_path_from_pattern(beg);
2317 if (!brace_path)
return -1;
2327 status = ruby_brace_expand(brace_path,
flags, push_caller, (
VALUE)&args, enc,
Qfalse);
2352 if (status)
return status;
2357 char *tmp = join_path(subpath,
namelen - seplen,
dirsep,
"", 0);
2358 if (!tmp)
return -1;
2361 if (status)
return status;
2367 if (magical || recursive) {
2370# if USE_NAME_ON_FS == USE_NAME_ON_FS_BY_FNMATCH
2371 char *plainname = 0;
2374# if USE_NAME_ON_FS == USE_NAME_ON_FS_BY_FNMATCH
2375 if (cur + 1 == end && (*cur)->type <=
ALPHA) {
2376 plainname = join_path(
path, pathlen,
dirsep, (*cur)->str,
strlen((*cur)->str));
2377 if (!plainname)
return -1;
2387# if FNM_SYSCASE || NORMALIZE_UTF8PATH
2388 if ((magical < 2) && !recursive && (errno == EACCES)) {
2397# if NORMALIZE_UTF8PATH
2398 if (!(norm_p || magical || recursive)) {
2403# ifdef HAVE_GETATTRLIST
2404 if (is_case_sensitive(dirp,
path) == 0)
2408 if (!glob_opendir(&globent, dirp,
flags, enc)) {
2418 while ((
dp = glob_getent(&globent,
flags, enc)) !=
NULL) {
2427 namlen =
dp->d_namlen;
2428 if (recursive &&
name[0] ==
'.') {
2436 else if (namlen == 2 &&
name[1] ==
'.') {
2442# if NORMALIZE_UTF8PATH
2443 if (norm_p && has_nonascii(
name, namlen)) {
2444 if (!
NIL_P(utf8str = rb_str_normalize_ospath(
name, namlen))) {
2459 new_pathtype =
dp->d_type;
2466 new_pathtype =
IFTODT(st.st_mode);
2478 for (cur = beg; cur < end; ++cur) {
2494 if (ruby_brace_expand(p->
str,
flags, dirent_match_brace,
2496 *new_end++ = p->
next;
2499# if USE_NAME_ON_FS == USE_NAME_ON_FS_BY_FNMATCH
2501 *new_end++ = p->
next;
2508 *new_end++ = p->
next;
2514 status = glob_helper(fd,
buf, baselen,
name -
buf - baselen + namlen, 1,
2515 new_pathtype, new_beg, new_end,
2516 flags, funcs, arg, enc);
2522 glob_dir_finish(&globent,
flags);
2527# if FNM_SYSCASE || NORMALIZE_UTF8PATH
2531 if (!copy_beg)
return -1;
2532 for (cur = beg; cur < end; ++cur)
2533 *copy_end++ = (*cur)->type <=
ALPHA ? *cur : 0;
2535 for (cur = copy_beg; cur < copy_end; ++cur) {
2556 *new_end++ = (*cur)->
next;
2557 for (cur2 = cur + 1; cur2 < copy_end; ++cur2) {
2558 if (*cur2 && fnmatch((*cur2)->str, enc,
name, flags) == 0) {
2559 *new_end++ = (*cur2)->
next;
2564 buf = join_path(path, pathlen, dirsep,
name,
len);
2571#if USE_NAME_ON_FS == USE_NAME_ON_FS_REAL_BASENAME
2572 if ((*cur)->type ==
ALPHA) {
2573 buf = replace_real_basename(
buf, pathlen + (dirsep != 0), enc,
2575 flags, &new_pathtype);
2579 status = glob_helper(fd,
buf, baselen,
2581 new_pathtype, new_beg, new_end,
2582 flags, funcs, arg, enc);
2596push_caller(
const char *path,
VALUE val,
void *enc)
2602 list = glob_make_pattern(path, path +
strlen(path), arg->
flags, enc);
2609 glob_free_pattern(list);
2613static int ruby_glob0(
const char *path,
int fd,
const char *base,
int flags,
2625push_glob0_caller(
const char *path,
VALUE val,
void *enc)
2628 return ruby_glob0(path,
arg->fd,
arg->base,
arg->flags,
arg->funcs,
arg->arg, enc);
2632ruby_glob0(
const char *path,
int fd,
const char *
base,
int flags,
2637 const char *
root, *start;
2639 size_t n, baselen = 0;
2640 int status, dirsep =
FALSE;
2642 start =
root = path;
2651 return ruby_brace_expand(path,
flags, push_glob0_caller, (
VALUE)&args, enc,
Qfalse);
2669 if (!
buf)
return -1;
2678 status = glob_helper(
fd,
buf, baselen, n-baselen, dirsep,
2681 glob_free_pattern(list);
2698rb_glob_caller(
const char *path,
VALUE a,
void *enc)
2709 rb_glob_caller, rb_glob_error,
2730#if defined _WIN32 || defined __APPLE__
2745 const char *p =
str;
2746 const char *pend = p +
strlen(p);
2748 const char *lbrace = 0, *rbrace = 0;
2749 int nest = 0, status = 0;
2752 if (*p ==
'{' && nest++ == 0) {
2755 if (*p ==
'}' && lbrace && --nest == 0) {
2759 if (*p ==
'\\' && escape) {
2765 if (lbrace && rbrace) {
2770 if (!
buf)
return -1;
2774 while (p < rbrace) {
2775 const char *
t = ++p;
2777 while (p < rbrace && !(*p ==
',' && nest == 0)) {
2778 if (*p ==
'{') nest++;
2779 if (*p ==
'}') nest--;
2780 if (*p ==
'\\' && escape) {
2781 if (++p == rbrace)
break;
2787 status = ruby_brace_expand(
buf, flags,
func, arg,
enc, var);
2792 else if (!lbrace && !rbrace) {
2807glob_brace(
const char *path,
VALUE val,
void *enc)
2819 flags &= ~GLOB_VERBOSE;
2840#if defined _WIN32 || defined __APPLE__
2848 args.func = push_pattern;
2856 if (!dirp->
dir) dir_closed();
2858 if ((fd = dirfd(dirp->
dir)) == -1)
2865#if defined _WIN32 || defined __APPLE__
2869 return ruby_glob0(
RSTRING_PTR(
str), fd, args.base, flags, &rb_glob_funcs,
2891 status = push_glob(ary,
str, base, flags);
2907 status = push_glob(ary,
str, base, flags);
2916dir_glob_option_base(
VALUE base)
2932dir_glob_option_sort(
VALUE sort)
2940 const int flags = dir_glob_option_sort(sort);
2941 base = dir_glob_option_base(base);
2943 return rb_push_glob(
RARRAY_AREF(args, 0), base, flags);
2945 return dir_globs(args, base, flags);
2952 const int flags =
NUM2INT(rflags) | dir_glob_option_sort(sort);
2953 base = dir_glob_option_base(base);
2955 ary = rb_push_glob(
str, base, flags);
2958 ary = dir_globs(ary, base, flags);
3046 return dir_each_entry(
dir, dir_yield,
Qnil,
TRUE);
3105 return dir_each_entry(
dir, dir_yield,
Qnil,
TRUE);
3152fnmatch_brace(
const char *pattern,
VALUE val,
void *
enc)
3159 if (enc_pattern != enc_path) {
3168 enc_pattern, &cr) !=
len)
3274 VALUE pattern, path;
3358nogvl_dir_empty_p(
void *
ptr)
3360 const char *path =
ptr;
3367 switch (gc_for_fd_with_gvl(e)) {
3374 if (e == ENOTDIR)
return (
void *)
Qfalse;
3380 if (!to_be_skipped(
dp)) {
3386 return (
void *)result;
3401 enum {false_on_notdir = 1};
3409#if defined HAVE_GETATTRLIST && defined ATTR_DIR_ENTRYCOUNT
3411 u_int32_t attrbuf[SIZEUP32(fsobj_tag_t)];
3412 struct attrlist al = {ATTR_BIT_MAP_COUNT, 0, ATTR_CMN_OBJTAG,};
3413 if (getattrlist(path, &al, attrbuf,
sizeof(attrbuf), 0) != 0)
3415 if (*(
const fsobj_tag_t *)(attrbuf+1) == VT_HFS) {
3417 al.dirattr = ATTR_DIR_ENTRYCOUNT;
3418 if (getattrlist(path, &al, attrbuf,
sizeof(attrbuf), 0) == 0) {
3419 if (attrbuf[0] >= 2 *
sizeof(u_int32_t))
3421 if (false_on_notdir)
return Qfalse;
#define offsetof(p_type, field)
VALUE rb_ary_push(VALUE ary, VALUE item)
VALUE rb_ary_each(VALUE ary)
VALUE rb_check_array_type(VALUE ary)
#define UNREACHABLE_RETURN
VALUE rb_int2inum(intptr_t n)
Our own, locale independent, character handling routines.
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
void rb_glob(const char *path, void(*func)(const char *, VALUE, void *), VALUE arg)
VALUE rb_dir_getwd_ospath(void)
char * strchr(char *, char)
#define READDIR(dir, enc)
struct rb_dirent rb_dirent_t
#define GLOB_JUMP_TAG(status)
int ruby_glob(const char *path, int flags, ruby_glob_func *func, VALUE arg)
#define sys_enc_warning_in(func, mesg, enc)
#define glob_call_func(func, path, arg, enc)
#define GLOB_ALLOC_N(type, n)
int ruby_brace_glob_with_enc(const char *str, int flags, ruby_glob_func *func, VALUE arg, rb_encoding *enc)
#define IF_NORMALIZE_UTF8PATH(something)
int ruby_glob_errfunc(const char *, VALUE, const void *, int)
#define GLOB_REALLOC(ptr, size)
#define GLOB_REALLOC_N(ptr, n)
#define sys_warning(val, enc)
#define GetDIR(obj, dirp)
int ruby_brace_glob(const char *str, int flags, ruby_glob_func *func, VALUE arg)
#define ENCINDEX_US_ASCII
int rb_enc_precise_mbclen(const char *p, const char *e, rb_encoding *enc)
rb_encoding * rb_utf8_encoding(void)
rb_encoding * rb_ascii8bit_encoding(void)
rb_encoding * rb_filesystem_encoding(void)
rb_encoding * rb_default_internal_encoding(void)
rb_encoding * rb_enc_get(VALUE obj)
int rb_enc_to_index(rb_encoding *enc)
rb_encoding * rb_enc_check(VALUE str1, VALUE str2)
int rb_enc_mbclen(const char *p, const char *e, rb_encoding *enc)
rb_encoding * rb_enc_compatible(VALUE str1, VALUE str2)
rb_encoding * rb_to_encoding(VALUE enc)
int rb_enc_toupper(int c, rb_encoding *enc)
rb_encoding * rb_usascii_encoding(void)
VALUE rb_enc_from_encoding(rb_encoding *encoding)
VALUE rb_enc_associate_index(VALUE obj, int idx)
char str[HTML_ESCAPE_MAX_LEN+1]
#define RSTRING_LEN(string)
#define RSTRING_PTR(string)
VALUE rb_get_path(VALUE obj)
char * rb_enc_path_end(const char *path, const char *end, rb_encoding *enc)
VALUE rb_str_encode_ospath(VALUE path)
char * rb_enc_path_skip_prefix(const char *path, const char *end, rb_encoding *enc)
VALUE rb_file_directory_p(VALUE obj, VALUE fname)
VALUE rb_home_dir_of(VALUE user, VALUE result)
void rb_file_const(const char *name, VALUE value)
VALUE rb_default_home_dir(VALUE result)
void rb_gc_mark(VALUE ptr)
int ruby_glob_func(const char *, VALUE, void *)
void rb_include_module(VALUE klass, VALUE module)
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
int rb_block_given_p(void)
Determines if the current method is given a block.
void rb_syserr_fail(int e, const char *mesg)
void rb_raise(VALUE exc, const char *fmt,...)
void rb_sys_enc_warning(rb_encoding *enc, const char *fmt,...)
int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type)
void rb_bug(const char *fmt,...)
void rb_syserr_enc_warning(int err, rb_encoding *enc, const char *fmt,...)
void rb_syserr_fail_str(int e, VALUE mesg)
VALUE rb_protect(VALUE(*proc)(VALUE), VALUE data, int *pstate)
Protects a function call from potential global escapes from the function.
void rb_warn_deprecated(const char *fmt, const char *suggest,...)
void * rb_check_typeddata(VALUE obj, const rb_data_type_t *data_type)
void rb_warn(const char *fmt,...)
VALUE rb_ensure(VALUE(*b_proc)(VALUE), VALUE data1, VALUE(*e_proc)(VALUE), VALUE data2)
An equivalent to ensure clause.
void rb_sys_fail(const char *mesg)
VALUE rb_cObject
Object class.
unsigned char match[65280+2]
unsigned in(void *in_desc, z_const unsigned char **buf)
void *PTR64 __attribute__((mode(DI)))
#define ENC_CODERANGE_7BIT
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
VALUE rb_enc_str_new_cstr(const char *, rb_encoding *)
VALUE rb_enc_str_new(const char *, long, rb_encoding *)
#define rb_enc_asciicompat(enc)
#define rb_enc_codepoint(p, e, enc)
int rb_enc_str_asciionly_p(VALUE)
long rb_str_coderange_scan_restartable(const char *, const char *, rb_encoding *, int *)
#define MBCLEN_CHARFOUND_P(ret)
VALUE rb_external_str_new_with_enc(const char *ptr, long len, rb_encoding *)
Thin wrapper to ruby/config.h.
VALUE rb_funcallv_kw(VALUE, ID, int, const VALUE *, int)
Defines RBIMPL_HAS_BUILTIN.
#define RETURN_ENUMERATOR(obj, argc, argv)
VALUE rb_str_resize(VALUE, long)
void rb_must_asciicompat(VALUE)
#define rb_utf8_str_new_cstr(str)
#define rb_str_new(str, len)
VALUE rb_str_subseq(VALUE, long, long)
VALUE rb_str_append(VALUE, VALUE)
#define rb_str_dup_frozen
#define rb_str_new_cstr(str)
VALUE rb_thread_current(void)
VALUE rb_class_name(VALUE)
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
ID rb_intern(const char *)
size_t strlcpy(char *, const char *, size_t)
void * memmove(void *, const void *, size_t)
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
void * rb_thread_call_without_gvl(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2)
void ruby_qsort(void *, const size_t, const size_t, int(*)(const void *, const void *, void *), void *)
Internal header for Array.
Internal header for Encoding.
#define rb_syserr_fail_path(err, path)
#define rb_sys_fail_path(path)
Internal header for File.
int rb_gc_for_fd(int err)
VALUE rb_external_str_with_enc(VALUE str, rb_encoding *eenc)
char * rb_str_to_cstr(VALUE str)
Internal header for RubyVM.
void rb_check_stack_overflow(void)
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
#define INVALID_HANDLE_VALUE
int memcmp(const void *s1, const void *s2, size_t len)
#define MEMCPY(p1, p2, type, n)
#define MEMZERO(p, type, n)
VALUE type(ANYARGS)
ANYARGS-ed function type.
#define RARRAY_AREF(a, i)
#define Data_Wrap_Struct(klass, mark, free, sval)
#define RUBY_DEFAULT_FREE
#define RB_OBJ_WRITE(a, slot, b)
WB for new reference from ‘a’ to ‘b’.
#define SafeStringValue(v)
#define RSTRING_GETMEM(str, ptrvar, lenvar)
#define StringValueCStr(v)
#define TypedData_Get_Struct(obj, type, data_type, sval)
@ RUBY_TYPED_FREE_IMMEDIATELY
@ RUBY_TYPED_WB_PROTECTED
#define TypedData_Make_Struct(klass, type, data_type, sval)
#define FilePathStringValue(v)
#define RB_PASS_CALLED_KEYWORDS
size_t strlen(const char *)
void(* func)(const char *, VALUE, void *)
struct glob_pattern * next
enum glob_pattern_type type
const ruby_glob_funcs_t * funcs
const ruby_glob_funcs_t * funcs
ruby_glob_errfunc * error
struct ruby_glob_entries_t::@15 nosort
struct ruby_glob_entries_t::@16 sort
void error(const char *msg)
VALUE rb_w32_conv_from_wchar(const WCHAR *wstr, rb_encoding *enc)
int rb_w32_reparse_symlink_p(const WCHAR *path)
int rb_w32_map_errno(DWORD)
WCHAR * rb_w32_mbstr_to_wstr(UINT, const char *, int, long *)