Ruby  2.0.0p247(2013-06-27revision41674)
dir.c
Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   dir.c -
00004 
00005   $Author: nagachika $
00006   created at: Wed Jan  5 09:51:01 JST 1994
00007 
00008   Copyright (C) 1993-2007 Yukihiro Matsumoto
00009   Copyright (C) 2000  Network Applied Communication Laboratory, Inc.
00010   Copyright (C) 2000  Information-technology Promotion Agency, Japan
00011 
00012 **********************************************************************/
00013 
00014 #include "ruby/ruby.h"
00015 #include "ruby/encoding.h"
00016 #include "internal.h"
00017 
00018 #include <sys/types.h>
00019 #include <sys/stat.h>
00020 
00021 #ifdef HAVE_UNISTD_H
00022 #include <unistd.h>
00023 #endif
00024 
00025 #if defined HAVE_DIRENT_H && !defined _WIN32
00026 # include <dirent.h>
00027 # define NAMLEN(dirent) strlen((dirent)->d_name)
00028 #elif defined HAVE_DIRECT_H && !defined _WIN32
00029 # include <direct.h>
00030 # define NAMLEN(dirent) strlen((dirent)->d_name)
00031 #else
00032 # define dirent direct
00033 # define NAMLEN(dirent) (dirent)->d_namlen
00034 # if HAVE_SYS_NDIR_H
00035 #  include <sys/ndir.h>
00036 # endif
00037 # if HAVE_SYS_DIR_H
00038 #  include <sys/dir.h>
00039 # endif
00040 # if HAVE_NDIR_H
00041 #  include <ndir.h>
00042 # endif
00043 # ifdef _WIN32
00044 #  include "win32/dir.h"
00045 # endif
00046 #endif
00047 #if defined(__native_client__) && defined(NACL_NEWLIB)
00048 # include "nacl/dirent.h"
00049 # include "nacl/stat.h"
00050 #endif
00051 
00052 #include <errno.h>
00053 
00054 #ifndef HAVE_STDLIB_H
00055 char *getenv();
00056 #endif
00057 
00058 #ifndef HAVE_STRING_H
00059 char *strchr(char*,char);
00060 #endif
00061 
00062 #include <ctype.h>
00063 
00064 #include "ruby/util.h"
00065 
00066 #if !defined HAVE_LSTAT && !defined lstat
00067 #define lstat stat
00068 #endif
00069 
00070 /* define system APIs */
00071 #ifdef _WIN32
00072 #undef chdir
00073 #define chdir(p) rb_w32_uchdir(p)
00074 #undef mkdir
00075 #define mkdir(p, m) rb_w32_umkdir((p), (m))
00076 #undef rmdir
00077 #define rmdir(p) rb_w32_urmdir(p)
00078 #undef opendir
00079 #define opendir(p) rb_w32_uopendir(p)
00080 #endif
00081 
00082 #define rb_sys_fail_path(path) rb_sys_fail_str(path)
00083 
00084 #define FNM_NOESCAPE    0x01
00085 #define FNM_PATHNAME    0x02
00086 #define FNM_DOTMATCH    0x04
00087 #define FNM_CASEFOLD    0x08
00088 #define FNM_EXTGLOB     0x10
00089 #if CASEFOLD_FILESYSTEM
00090 #define FNM_SYSCASE     FNM_CASEFOLD
00091 #else
00092 #define FNM_SYSCASE     0
00093 #endif
00094 
00095 #define FNM_NOMATCH     1
00096 #define FNM_ERROR       2
00097 
00098 # define Next(p, e, enc) ((p)+ rb_enc_mbclen((p), (e), (enc)))
00099 # define Inc(p, e, enc) ((p) = Next((p), (e), (enc)))
00100 
00101 static char *
00102 bracket(
00103     const char *p, /* pattern (next to '[') */
00104     const char *pend,
00105     const char *s, /* string */
00106     const char *send,
00107     int flags,
00108     rb_encoding *enc)
00109 {
00110     const int nocase = flags & FNM_CASEFOLD;
00111     const int escape = !(flags & FNM_NOESCAPE);
00112     unsigned int c1, c2;
00113     int r;
00114     int ok = 0, not = 0;
00115 
00116     if (p >= pend) return NULL;
00117     if (*p == '!' || *p == '^') {
00118         not = 1;
00119         p++;
00120     }
00121 
00122     while (*p != ']') {
00123         const char *t1 = p;
00124         if (escape && *t1 == '\\')
00125             t1++;
00126         if (!*t1)
00127             return NULL;
00128         p = t1 + (r = rb_enc_mbclen(t1, pend, enc));
00129         if (p >= pend) return NULL;
00130         if (p[0] == '-' && p[1] != ']') {
00131             const char *t2 = p + 1;
00132             int r2;
00133             if (escape && *t2 == '\\')
00134                 t2++;
00135             if (!*t2)
00136                 return NULL;
00137             p = t2 + (r2 = rb_enc_mbclen(t2, pend, enc));
00138             if (ok) continue;
00139             if ((r <= (send-s) && memcmp(t1, s, r) == 0) ||
00140                 (r2 <= (send-s) && memcmp(t2, s, r2) == 0)) {
00141                 ok = 1;
00142                 continue;
00143             }
00144             c1 = rb_enc_codepoint(s, send, enc);
00145             if (nocase) c1 = rb_enc_toupper(c1, enc);
00146             c2 = rb_enc_codepoint(t1, pend, enc);
00147             if (nocase) c2 = rb_enc_toupper(c2, enc);
00148             if (c1 < c2) continue;
00149             c2 = rb_enc_codepoint(t2, pend, enc);
00150             if (nocase) c2 = rb_enc_toupper(c2, enc);
00151             if (c1 > c2) continue;
00152         }
00153         else {
00154             if (ok) continue;
00155             if (r <= (send-s) && memcmp(t1, s, r) == 0) {
00156                 ok = 1;
00157                 continue;
00158             }
00159             if (!nocase) continue;
00160             c1 = rb_enc_toupper(rb_enc_codepoint(s, send, enc), enc);
00161             c2 = rb_enc_toupper(rb_enc_codepoint(p, pend, enc), enc);
00162             if (c1 != c2) continue;
00163         }
00164         ok = 1;
00165     }
00166 
00167     return ok == not ? NULL : (char *)p + 1;
00168 }
00169 
00170 /* If FNM_PATHNAME is set, only path element will be matched. (upto '/' or '\0')
00171    Otherwise, entire string will be matched.
00172    End marker itself won't be compared.
00173    And if function succeeds, *pcur reaches end marker.
00174 */
00175 #define UNESCAPE(p) (escape && *(p) == '\\' ? (p) + 1 : (p))
00176 #define ISEND(p) (!*(p) || (pathname && *(p) == '/'))
00177 #define RETURN(val) return *pcur = p, *scur = s, (val);
00178 
00179 static int
00180 fnmatch_helper(
00181     const char **pcur, /* pattern */
00182     const char **scur, /* string */
00183     int flags,
00184     rb_encoding *enc)
00185 {
00186     const int period = !(flags & FNM_DOTMATCH);
00187     const int pathname = flags & FNM_PATHNAME;
00188     const int escape = !(flags & FNM_NOESCAPE);
00189     const int nocase = flags & FNM_CASEFOLD;
00190 
00191     const char *ptmp = 0;
00192     const char *stmp = 0;
00193 
00194     const char *p = *pcur;
00195     const char *pend = p + strlen(p);
00196     const char *s = *scur;
00197     const char *send = s + strlen(s);
00198 
00199     int r;
00200 
00201     if (period && *s == '.' && *UNESCAPE(p) != '.') /* leading period */
00202         RETURN(FNM_NOMATCH);
00203 
00204     while (1) {
00205         switch (*p) {
00206           case '*':
00207             do { p++; } while (*p == '*');
00208             if (ISEND(UNESCAPE(p))) {
00209                 p = UNESCAPE(p);
00210                 RETURN(0);
00211             }
00212             if (ISEND(s))
00213                 RETURN(FNM_NOMATCH);
00214             ptmp = p;
00215             stmp = s;
00216             continue;
00217 
00218           case '?':
00219             if (ISEND(s))
00220                 RETURN(FNM_NOMATCH);
00221             p++;
00222             Inc(s, send, enc);
00223             continue;
00224 
00225           case '[': {
00226             const char *t;
00227             if (ISEND(s))
00228                 RETURN(FNM_NOMATCH);
00229             if ((t = bracket(p + 1, pend, s, send, flags, enc)) != 0) {
00230                 p = t;
00231                 Inc(s, send, enc);
00232                 continue;
00233             }
00234             goto failed;
00235           }
00236         }
00237 
00238         /* ordinary */
00239         p = UNESCAPE(p);
00240         if (ISEND(s))
00241             RETURN(ISEND(p) ? 0 : FNM_NOMATCH);
00242         if (ISEND(p))
00243             goto failed;
00244         r = rb_enc_precise_mbclen(p, pend, enc);
00245         if (!MBCLEN_CHARFOUND_P(r))
00246             goto failed;
00247         if (r <= (send-s) && memcmp(p, s, r) == 0) {
00248             p += r;
00249             s += r;
00250             continue;
00251         }
00252         if (!nocase) goto failed;
00253         if (rb_enc_toupper(rb_enc_codepoint(p, pend, enc), enc) !=
00254             rb_enc_toupper(rb_enc_codepoint(s, send, enc), enc))
00255             goto failed;
00256         p += r;
00257         Inc(s, send, enc);
00258         continue;
00259 
00260       failed: /* try next '*' position */
00261         if (ptmp && stmp) {
00262             p = ptmp;
00263             Inc(stmp, send, enc); /* !ISEND(*stmp) */
00264             s = stmp;
00265             continue;
00266         }
00267         RETURN(FNM_NOMATCH);
00268     }
00269 }
00270 
00271 static int
00272 fnmatch(
00273     const char *pattern,
00274     rb_encoding *enc,
00275     const char *string,
00276     int flags)
00277 {
00278     const char *p = pattern;
00279     const char *s = string;
00280     const char *send = s + strlen(string);
00281     const int period = !(flags & FNM_DOTMATCH);
00282     const int pathname = flags & FNM_PATHNAME;
00283 
00284     const char *ptmp = 0;
00285     const char *stmp = 0;
00286 
00287     if (pathname) {
00288         while (1) {
00289             if (p[0] == '*' && p[1] == '*' && p[2] == '/') {
00290                 do { p += 3; } while (p[0] == '*' && p[1] == '*' && p[2] == '/');
00291                 ptmp = p;
00292                 stmp = s;
00293             }
00294             if (fnmatch_helper(&p, &s, flags, enc) == 0) {
00295                 while (*s && *s != '/') Inc(s, send, enc);
00296                 if (*p && *s) {
00297                     p++;
00298                     s++;
00299                     continue;
00300                 }
00301                 if (!*p && !*s)
00302                     return 0;
00303             }
00304             /* failed : try next recursion */
00305             if (ptmp && stmp && !(period && *stmp == '.')) {
00306                 while (*stmp && *stmp != '/') Inc(stmp, send, enc);
00307                 if (*stmp) {
00308                     p = ptmp;
00309                     stmp++;
00310                     s = stmp;
00311                     continue;
00312                 }
00313             }
00314             return FNM_NOMATCH;
00315         }
00316     }
00317     else
00318         return fnmatch_helper(&p, &s, flags, enc);
00319 }
00320 
00321 VALUE rb_cDir;
00322 
00323 struct dir_data {
00324     DIR *dir;
00325     VALUE path;
00326     rb_encoding *enc;
00327 };
00328 
00329 static void
00330 dir_mark(void *ptr)
00331 {
00332     struct dir_data *dir = ptr;
00333     rb_gc_mark(dir->path);
00334 }
00335 
00336 static void
00337 dir_free(void *ptr)
00338 {
00339     struct dir_data *dir = ptr;
00340     if (dir) {
00341         if (dir->dir) closedir(dir->dir);
00342     }
00343     xfree(dir);
00344 }
00345 
00346 static size_t
00347 dir_memsize(const void *ptr)
00348 {
00349     return ptr ? sizeof(struct dir_data) : 0;
00350 }
00351 
00352 static const rb_data_type_t dir_data_type = {
00353     "dir",
00354     {dir_mark, dir_free, dir_memsize,},
00355 };
00356 
00357 static VALUE dir_close(VALUE);
00358 
00359 #define GlobPathValue(str, safe) \
00360     /* can contain null bytes as separators */  \
00361     (!RB_TYPE_P((str), T_STRING) ?              \
00362      (void)FilePathValue(str) :                 \
00363      (void)(check_safe_glob((str), (safe)),             \
00364       check_glob_encoding(str), (str)))
00365 #define check_safe_glob(str, safe) ((safe) ? rb_check_safe_obj(str) : (void)0)
00366 #define check_glob_encoding(str) rb_enc_check((str), rb_enc_from_encoding(rb_usascii_encoding()))
00367 
00368 static VALUE
00369 dir_s_alloc(VALUE klass)
00370 {
00371     struct dir_data *dirp;
00372     VALUE obj = TypedData_Make_Struct(klass, struct dir_data, &dir_data_type, dirp);
00373 
00374     dirp->dir = NULL;
00375     dirp->path = Qnil;
00376     dirp->enc = NULL;
00377 
00378     return obj;
00379 }
00380 
00381 /*
00382  *  call-seq:
00383  *     Dir.new( string ) -> aDir
00384  *
00385  *  Returns a new directory object for the named directory.
00386  */
00387 static VALUE
00388 dir_initialize(int argc, VALUE *argv, VALUE dir)
00389 {
00390     struct dir_data *dp;
00391     rb_encoding  *fsenc;
00392     VALUE dirname, opt, orig;
00393     static VALUE sym_enc;
00394 
00395     if (!sym_enc) {
00396         sym_enc = ID2SYM(rb_intern("encoding"));
00397     }
00398     fsenc = rb_filesystem_encoding();
00399 
00400     rb_scan_args(argc, argv, "1:", &dirname, &opt);
00401 
00402     if (!NIL_P(opt)) {
00403         VALUE enc = rb_hash_aref(opt, sym_enc);
00404         if (!NIL_P(enc)) {
00405             fsenc = rb_to_encoding(enc);
00406         }
00407     }
00408 
00409     GlobPathValue(dirname, FALSE);
00410     orig = rb_str_dup_frozen(dirname);
00411     dirname = rb_str_encode_ospath(dirname);
00412     dirname = rb_str_dup_frozen(dirname);
00413 
00414     TypedData_Get_Struct(dir, struct dir_data, &dir_data_type, dp);
00415     if (dp->dir) closedir(dp->dir);
00416     dp->dir = NULL;
00417     dp->path = Qnil;
00418     dp->enc = fsenc;
00419     dp->dir = opendir(RSTRING_PTR(dirname));
00420     if (dp->dir == NULL) {
00421         if (errno == EMFILE || errno == ENFILE) {
00422             rb_gc();
00423             dp->dir = opendir(RSTRING_PTR(dirname));
00424         }
00425         if (dp->dir == NULL) {
00426             rb_sys_fail_path(orig);
00427         }
00428     }
00429     dp->path = orig;
00430 
00431     return dir;
00432 }
00433 
00434 /*
00435  *  call-seq:
00436  *     Dir.open( string ) -> aDir
00437  *     Dir.open( string ) {| aDir | block } -> anObject
00438  *
00439  *  With no block, <code>open</code> is a synonym for
00440  *  <code>Dir::new</code>. If a block is present, it is passed
00441  *  <i>aDir</i> as a parameter. The directory is closed at the end of
00442  *  the block, and <code>Dir::open</code> returns the value of the
00443  *  block.
00444  */
00445 static VALUE
00446 dir_s_open(int argc, VALUE *argv, VALUE klass)
00447 {
00448     struct dir_data *dp;
00449     VALUE dir = TypedData_Make_Struct(klass, struct dir_data, &dir_data_type, dp);
00450 
00451     dir_initialize(argc, argv, dir);
00452     if (rb_block_given_p()) {
00453         return rb_ensure(rb_yield, dir, dir_close, dir);
00454     }
00455 
00456     return dir;
00457 }
00458 
00459 static void
00460 dir_closed(void)
00461 {
00462     rb_raise(rb_eIOError, "closed directory");
00463 }
00464 
00465 static struct dir_data *
00466 dir_check(VALUE dir)
00467 {
00468     struct dir_data *dirp;
00469     if (!OBJ_UNTRUSTED(dir) && rb_safe_level() >= 4)
00470         rb_raise(rb_eSecurityError, "Insecure: operation on trusted Dir");
00471     rb_check_frozen(dir);
00472     dirp = rb_check_typeddata(dir, &dir_data_type);
00473     if (!dirp->dir) dir_closed();
00474     return dirp;
00475 }
00476 
00477 #define GetDIR(obj, dirp) ((dirp) = dir_check(obj))
00478 
00479 
00480 /*
00481  *  call-seq:
00482  *     dir.inspect -> string
00483  *
00484  *  Return a string describing this Dir object.
00485  */
00486 static VALUE
00487 dir_inspect(VALUE dir)
00488 {
00489     struct dir_data *dirp;
00490 
00491     TypedData_Get_Struct(dir, struct dir_data, &dir_data_type, dirp);
00492     if (!NIL_P(dirp->path)) {
00493         VALUE str = rb_str_new_cstr("#<");
00494         rb_str_append(str, rb_class_name(CLASS_OF(dir)));
00495         rb_str_cat2(str, ":");
00496         rb_str_append(str, dirp->path);
00497         rb_str_cat2(str, ">");
00498         return str;
00499     }
00500     return rb_funcall(dir, rb_intern("to_s"), 0, 0);
00501 }
00502 
00503 /*
00504  *  call-seq:
00505  *     dir.path -> string or nil
00506  *
00507  *  Returns the path parameter passed to <em>dir</em>'s constructor.
00508  *
00509  *     d = Dir.new("..")
00510  *     d.path   #=> ".."
00511  */
00512 static VALUE
00513 dir_path(VALUE dir)
00514 {
00515     struct dir_data *dirp;
00516 
00517     TypedData_Get_Struct(dir, struct dir_data, &dir_data_type, dirp);
00518     if (NIL_P(dirp->path)) return Qnil;
00519     return rb_str_dup(dirp->path);
00520 }
00521 
00522 #if defined HAVE_READDIR_R
00523 # define READDIR(dir, enc, entry, dp) (readdir_r((dir), (entry), &(dp)) == 0 && (dp) != 0)
00524 #elif defined _WIN32
00525 # define READDIR(dir, enc, entry, dp) (((dp) = rb_w32_readdir((dir), (enc))) != 0)
00526 #else
00527 # define READDIR(dir, enc, entry, dp) (((dp) = readdir(dir)) != 0)
00528 #endif
00529 #if defined HAVE_READDIR_R
00530 # define IF_HAVE_READDIR_R(something) something
00531 #else
00532 # define IF_HAVE_READDIR_R(something) /* nothing */
00533 #endif
00534 
00535 #if defined SIZEOF_STRUCT_DIRENT_TOO_SMALL
00536 # include <limits.h>
00537 # define NAME_MAX_FOR_STRUCT_DIRENT 255
00538 # if defined NAME_MAX
00539 #  if NAME_MAX_FOR_STRUCT_DIRENT < NAME_MAX
00540 #   undef  NAME_MAX_FOR_STRUCT_DIRENT
00541 #   define NAME_MAX_FOR_STRUCT_DIRENT NAME_MAX
00542 #  endif
00543 # endif
00544 # if defined _POSIX_NAME_MAX
00545 #  if NAME_MAX_FOR_STRUCT_DIRENT < _POSIX_NAME_MAX
00546 #   undef  NAME_MAX_FOR_STRUCT_DIRENT
00547 #   define NAME_MAX_FOR_STRUCT_DIRENT _POSIX_NAME_MAX
00548 #  endif
00549 # endif
00550 # if defined _XOPEN_NAME_MAX
00551 #  if NAME_MAX_FOR_STRUCT_DIRENT < _XOPEN_NAME_MAX
00552 #   undef  NAME_MAX_FOR_STRUCT_DIRENT
00553 #   define NAME_MAX_FOR_STRUCT_DIRENT _XOPEN_NAME_MAX
00554 #  endif
00555 # endif
00556 # define DEFINE_STRUCT_DIRENT \
00557   union { \
00558     struct dirent dirent; \
00559     char dummy[offsetof(struct dirent, d_name) + \
00560                NAME_MAX_FOR_STRUCT_DIRENT + 1]; \
00561   }
00562 # define STRUCT_DIRENT(entry) ((entry).dirent)
00563 #else
00564 # define DEFINE_STRUCT_DIRENT struct dirent
00565 # define STRUCT_DIRENT(entry) (entry)
00566 #endif
00567 
00568 /*
00569  *  call-seq:
00570  *     dir.read -> string or nil
00571  *
00572  *  Reads the next entry from <em>dir</em> and returns it as a string.
00573  *  Returns <code>nil</code> at the end of the stream.
00574  *
00575  *     d = Dir.new("testdir")
00576  *     d.read   #=> "."
00577  *     d.read   #=> ".."
00578  *     d.read   #=> "config.h"
00579  */
00580 static VALUE
00581 dir_read(VALUE dir)
00582 {
00583     struct dir_data *dirp;
00584     struct dirent *dp;
00585     IF_HAVE_READDIR_R(DEFINE_STRUCT_DIRENT entry);
00586 
00587     GetDIR(dir, dirp);
00588     errno = 0;
00589     if (READDIR(dirp->dir, dirp->enc, &STRUCT_DIRENT(entry), dp)) {
00590         return rb_external_str_new_with_enc(dp->d_name, NAMLEN(dp), dirp->enc);
00591     }
00592     else {
00593         if (errno != 0) rb_sys_fail(0);
00594         return Qnil;            /* end of stream */
00595     }
00596 }
00597 
00598 /*
00599  *  call-seq:
00600  *     dir.each { |filename| block }  -> dir
00601  *     dir.each                       -> an_enumerator
00602  *
00603  *  Calls the block once for each entry in this directory, passing the
00604  *  filename of each entry as a parameter to the block.
00605  *
00606  *  If no block is given, an enumerator is returned instead.
00607  *
00608  *     d = Dir.new("testdir")
00609  *     d.each  {|x| puts "Got #{x}" }
00610  *
00611  *  <em>produces:</em>
00612  *
00613  *     Got .
00614  *     Got ..
00615  *     Got config.h
00616  *     Got main.rb
00617  */
00618 static VALUE
00619 dir_each(VALUE dir)
00620 {
00621     struct dir_data *dirp;
00622     struct dirent *dp;
00623     IF_HAVE_READDIR_R(DEFINE_STRUCT_DIRENT entry);
00624 
00625     RETURN_ENUMERATOR(dir, 0, 0);
00626     GetDIR(dir, dirp);
00627     rewinddir(dirp->dir);
00628     while (READDIR(dirp->dir, dirp->enc, &STRUCT_DIRENT(entry), dp)) {
00629         rb_yield(rb_external_str_new_with_enc(dp->d_name, NAMLEN(dp), dirp->enc));
00630         if (dirp->dir == NULL) dir_closed();
00631     }
00632     return dir;
00633 }
00634 
00635 #ifdef HAVE_TELLDIR
00636 /*
00637  *  call-seq:
00638  *     dir.pos -> integer
00639  *     dir.tell -> integer
00640  *
00641  *  Returns the current position in <em>dir</em>. See also
00642  *  <code>Dir#seek</code>.
00643  *
00644  *     d = Dir.new("testdir")
00645  *     d.tell   #=> 0
00646  *     d.read   #=> "."
00647  *     d.tell   #=> 12
00648  */
00649 static VALUE
00650 dir_tell(VALUE dir)
00651 {
00652     struct dir_data *dirp;
00653     long pos;
00654 
00655     GetDIR(dir, dirp);
00656     pos = telldir(dirp->dir);
00657     return rb_int2inum(pos);
00658 }
00659 #else
00660 #define dir_tell rb_f_notimplement
00661 #endif
00662 
00663 #ifdef HAVE_SEEKDIR
00664 /*
00665  *  call-seq:
00666  *     dir.seek( integer ) -> dir
00667  *
00668  *  Seeks to a particular location in <em>dir</em>. <i>integer</i>
00669  *  must be a value returned by <code>Dir#tell</code>.
00670  *
00671  *     d = Dir.new("testdir")   #=> #<Dir:0x401b3c40>
00672  *     d.read                   #=> "."
00673  *     i = d.tell               #=> 12
00674  *     d.read                   #=> ".."
00675  *     d.seek(i)                #=> #<Dir:0x401b3c40>
00676  *     d.read                   #=> ".."
00677  */
00678 static VALUE
00679 dir_seek(VALUE dir, VALUE pos)
00680 {
00681     struct dir_data *dirp;
00682     long p = NUM2LONG(pos);
00683 
00684     GetDIR(dir, dirp);
00685     seekdir(dirp->dir, p);
00686     return dir;
00687 }
00688 #else
00689 #define dir_seek rb_f_notimplement
00690 #endif
00691 
00692 #ifdef HAVE_SEEKDIR
00693 /*
00694  *  call-seq:
00695  *     dir.pos( integer ) -> integer
00696  *
00697  *  Synonym for <code>Dir#seek</code>, but returns the position
00698  *  parameter.
00699  *
00700  *     d = Dir.new("testdir")   #=> #<Dir:0x401b3c40>
00701  *     d.read                   #=> "."
00702  *     i = d.pos                #=> 12
00703  *     d.read                   #=> ".."
00704  *     d.pos = i                #=> 12
00705  *     d.read                   #=> ".."
00706  */
00707 static VALUE
00708 dir_set_pos(VALUE dir, VALUE pos)
00709 {
00710     dir_seek(dir, pos);
00711     return pos;
00712 }
00713 #else
00714 #define dir_set_pos rb_f_notimplement
00715 #endif
00716 
00717 /*
00718  *  call-seq:
00719  *     dir.rewind -> dir
00720  *
00721  *  Repositions <em>dir</em> to the first entry.
00722  *
00723  *     d = Dir.new("testdir")
00724  *     d.read     #=> "."
00725  *     d.rewind   #=> #<Dir:0x401b3fb0>
00726  *     d.read     #=> "."
00727  */
00728 static VALUE
00729 dir_rewind(VALUE dir)
00730 {
00731     struct dir_data *dirp;
00732 
00733     if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(dir)) {
00734         rb_raise(rb_eSecurityError, "Insecure: can't close");
00735     }
00736     GetDIR(dir, dirp);
00737     rewinddir(dirp->dir);
00738     return dir;
00739 }
00740 
00741 /*
00742  *  call-seq:
00743  *     dir.close -> nil
00744  *
00745  *  Closes the directory stream. Any further attempts to access
00746  *  <em>dir</em> will raise an <code>IOError</code>.
00747  *
00748  *     d = Dir.new("testdir")
00749  *     d.close   #=> nil
00750  */
00751 static VALUE
00752 dir_close(VALUE dir)
00753 {
00754     struct dir_data *dirp;
00755 
00756     GetDIR(dir, dirp);
00757     closedir(dirp->dir);
00758     dirp->dir = NULL;
00759 
00760     return Qnil;
00761 }
00762 
00763 static void
00764 dir_chdir(VALUE path)
00765 {
00766     if (chdir(RSTRING_PTR(path)) < 0)
00767         rb_sys_fail_path(path);
00768 }
00769 
00770 static int chdir_blocking = 0;
00771 static VALUE chdir_thread = Qnil;
00772 
00773 struct chdir_data {
00774     VALUE old_path, new_path;
00775     int done;
00776 };
00777 
00778 static VALUE
00779 chdir_yield(struct chdir_data *args)
00780 {
00781     dir_chdir(args->new_path);
00782     args->done = TRUE;
00783     chdir_blocking++;
00784     if (chdir_thread == Qnil)
00785         chdir_thread = rb_thread_current();
00786     return rb_yield(args->new_path);
00787 }
00788 
00789 static VALUE
00790 chdir_restore(struct chdir_data *args)
00791 {
00792     if (args->done) {
00793         chdir_blocking--;
00794         if (chdir_blocking == 0)
00795             chdir_thread = Qnil;
00796         dir_chdir(args->old_path);
00797     }
00798     return Qnil;
00799 }
00800 
00801 /*
00802  *  call-seq:
00803  *     Dir.chdir( [ string] ) -> 0
00804  *     Dir.chdir( [ string] ) {| path | block }  -> anObject
00805  *
00806  *  Changes the current working directory of the process to the given
00807  *  string. When called without an argument, changes the directory to
00808  *  the value of the environment variable <code>HOME</code>, or
00809  *  <code>LOGDIR</code>. <code>SystemCallError</code> (probably
00810  *  <code>Errno::ENOENT</code>) if the target directory does not exist.
00811  *
00812  *  If a block is given, it is passed the name of the new current
00813  *  directory, and the block is executed with that as the current
00814  *  directory. The original working directory is restored when the block
00815  *  exits. The return value of <code>chdir</code> is the value of the
00816  *  block. <code>chdir</code> blocks can be nested, but in a
00817  *  multi-threaded program an error will be raised if a thread attempts
00818  *  to open a <code>chdir</code> block while another thread has one
00819  *  open.
00820  *
00821  *     Dir.chdir("/var/spool/mail")
00822  *     puts Dir.pwd
00823  *     Dir.chdir("/tmp") do
00824  *       puts Dir.pwd
00825  *       Dir.chdir("/usr") do
00826  *         puts Dir.pwd
00827  *       end
00828  *       puts Dir.pwd
00829  *     end
00830  *     puts Dir.pwd
00831  *
00832  *  <em>produces:</em>
00833  *
00834  *     /var/spool/mail
00835  *     /tmp
00836  *     /usr
00837  *     /tmp
00838  *     /var/spool/mail
00839  */
00840 static VALUE
00841 dir_s_chdir(int argc, VALUE *argv, VALUE obj)
00842 {
00843     VALUE path = Qnil;
00844 
00845     rb_secure(2);
00846     if (rb_scan_args(argc, argv, "01", &path) == 1) {
00847         FilePathValue(path);
00848         path = rb_str_encode_ospath(path);
00849     }
00850     else {
00851         const char *dist = getenv("HOME");
00852         if (!dist) {
00853             dist = getenv("LOGDIR");
00854             if (!dist) rb_raise(rb_eArgError, "HOME/LOGDIR not set");
00855         }
00856         path = rb_str_new2(dist);
00857     }
00858 
00859     if (chdir_blocking > 0) {
00860         if (!rb_block_given_p() || rb_thread_current() != chdir_thread)
00861             rb_warn("conflicting chdir during another chdir block");
00862     }
00863 
00864     if (rb_block_given_p()) {
00865         struct chdir_data args;
00866 
00867         args.old_path = rb_str_encode_ospath(rb_dir_getwd());
00868         args.new_path = path;
00869         args.done = FALSE;
00870         return rb_ensure(chdir_yield, (VALUE)&args, chdir_restore, (VALUE)&args);
00871     }
00872     dir_chdir(path);
00873 
00874     return INT2FIX(0);
00875 }
00876 
00877 VALUE
00878 rb_dir_getwd(void)
00879 {
00880     char *path;
00881     VALUE cwd;
00882 
00883     rb_secure(4);
00884     path = my_getcwd();
00885     cwd = rb_tainted_str_new2(path);
00886     rb_enc_associate(cwd, rb_filesystem_encoding());
00887 
00888     xfree(path);
00889     return cwd;
00890 }
00891 
00892 /*
00893  *  call-seq:
00894  *     Dir.getwd -> string
00895  *     Dir.pwd -> string
00896  *
00897  *  Returns the path to the current working directory of this process as
00898  *  a string.
00899  *
00900  *     Dir.chdir("/tmp")   #=> 0
00901  *     Dir.getwd           #=> "/tmp"
00902  */
00903 static VALUE
00904 dir_s_getwd(VALUE dir)
00905 {
00906     return rb_dir_getwd();
00907 }
00908 
00909 static void
00910 check_dirname(volatile VALUE *dir)
00911 {
00912     VALUE d = *dir;
00913     char *path, *pend;
00914     long len;
00915     rb_encoding *enc;
00916 
00917     rb_secure(2);
00918     FilePathValue(d);
00919     enc = rb_enc_get(d);
00920     RSTRING_GETMEM(d, path, len);
00921     pend = path + len;
00922     pend = rb_enc_path_end(rb_enc_path_skip_prefix(path, pend, enc), pend, enc);
00923     if (pend - path < len) {
00924         d = rb_str_subseq(d, 0, pend - path);
00925     }
00926     *dir = rb_str_encode_ospath(d);
00927 }
00928 
00929 #if defined(HAVE_CHROOT)
00930 /*
00931  *  call-seq:
00932  *     Dir.chroot( string ) -> 0
00933  *
00934  *  Changes this process's idea of the file system root. Only a
00935  *  privileged process may make this call. Not available on all
00936  *  platforms. On Unix systems, see <code>chroot(2)</code> for more
00937  *  information.
00938  */
00939 static VALUE
00940 dir_s_chroot(VALUE dir, VALUE path)
00941 {
00942     check_dirname(&path);
00943     if (chroot(RSTRING_PTR(path)) == -1)
00944         rb_sys_fail_path(path);
00945 
00946     return INT2FIX(0);
00947 }
00948 #else
00949 #define dir_s_chroot rb_f_notimplement
00950 #endif
00951 
00952 /*
00953  *  call-seq:
00954  *     Dir.mkdir( string [, integer] ) -> 0
00955  *
00956  *  Makes a new directory named by <i>string</i>, with permissions
00957  *  specified by the optional parameter <i>anInteger</i>. The
00958  *  permissions may be modified by the value of
00959  *  <code>File::umask</code>, and are ignored on NT. Raises a
00960  *  <code>SystemCallError</code> if the directory cannot be created. See
00961  *  also the discussion of permissions in the class documentation for
00962  *  <code>File</code>.
00963  *
00964  *    Dir.mkdir(File.join(Dir.home, ".foo"), 0700) #=> 0
00965  *
00966  */
00967 static VALUE
00968 dir_s_mkdir(int argc, VALUE *argv, VALUE obj)
00969 {
00970     VALUE path, vmode;
00971     int mode;
00972 
00973     if (rb_scan_args(argc, argv, "11", &path, &vmode) == 2) {
00974         mode = NUM2INT(vmode);
00975     }
00976     else {
00977         mode = 0777;
00978     }
00979 
00980     check_dirname(&path);
00981     if (mkdir(RSTRING_PTR(path), mode) == -1)
00982         rb_sys_fail_path(path);
00983 
00984     return INT2FIX(0);
00985 }
00986 
00987 /*
00988  *  call-seq:
00989  *     Dir.delete( string ) -> 0
00990  *     Dir.rmdir( string ) -> 0
00991  *     Dir.unlink( string ) -> 0
00992  *
00993  *  Deletes the named directory. Raises a subclass of
00994  *  <code>SystemCallError</code> if the directory isn't empty.
00995  */
00996 static VALUE
00997 dir_s_rmdir(VALUE obj, VALUE dir)
00998 {
00999     check_dirname(&dir);
01000     if (rmdir(RSTRING_PTR(dir)) < 0)
01001         rb_sys_fail_path(dir);
01002 
01003     return INT2FIX(0);
01004 }
01005 
01006 static VALUE
01007 sys_warning_1(VALUE mesg)
01008 {
01009     rb_sys_warning("%s:%s", strerror(errno), (const char *)mesg);
01010     return Qnil;
01011 }
01012 
01013 #define GLOB_VERBOSE    (1U << (sizeof(int) * CHAR_BIT - 1))
01014 #define sys_warning(val) \
01015     (void)((flags & GLOB_VERBOSE) && rb_protect(sys_warning_1, (VALUE)(val), 0))
01016 
01017 #define GLOB_ALLOC(type) ((type *)malloc(sizeof(type)))
01018 #define GLOB_ALLOC_N(type, n) ((type *)malloc(sizeof(type) * (n)))
01019 #define GLOB_FREE(ptr) free(ptr)
01020 #define GLOB_JUMP_TAG(status) (((status) == -1) ? rb_memerror() : rb_jump_tag(status))
01021 
01022 /*
01023  * ENOTDIR can be returned by stat(2) if a non-leaf element of the path
01024  * is not a directory.
01025  */
01026 #define to_be_ignored(e) ((e) == ENOENT || (e) == ENOTDIR)
01027 
01028 /* System call with warning */
01029 static int
01030 do_stat(const char *path, struct stat *pst, int flags)
01031 
01032 {
01033     int ret = stat(path, pst);
01034     if (ret < 0 && !to_be_ignored(errno))
01035         sys_warning(path);
01036 
01037     return ret;
01038 }
01039 
01040 static int
01041 do_lstat(const char *path, struct stat *pst, int flags)
01042 {
01043     int ret = lstat(path, pst);
01044     if (ret < 0 && !to_be_ignored(errno))
01045         sys_warning(path);
01046 
01047     return ret;
01048 }
01049 
01050 static DIR *
01051 do_opendir(const char *path, int flags, rb_encoding *enc)
01052 {
01053     DIR *dirp;
01054 #ifdef _WIN32
01055     volatile VALUE tmp;
01056     if (enc != rb_usascii_encoding() &&
01057         enc != rb_ascii8bit_encoding() &&
01058         enc != rb_utf8_encoding()) {
01059         tmp = rb_enc_str_new(path, strlen(path), enc);
01060         tmp = rb_str_encode_ospath(tmp);
01061         path = RSTRING_PTR(tmp);
01062     }
01063 #endif
01064     dirp = opendir(path);
01065     if (dirp == NULL && !to_be_ignored(errno))
01066         sys_warning(path);
01067 
01068     return dirp;
01069 }
01070 
01071 /* Return nonzero if S has any special globbing chars in it.  */
01072 static int
01073 has_magic(const char *p, const char *pend, int flags, rb_encoding *enc)
01074 {
01075     const int escape = !(flags & FNM_NOESCAPE);
01076     const int nocase = flags & FNM_CASEFOLD;
01077 
01078     register char c;
01079 
01080     while (p < pend && (c = *p++) != 0) {
01081         switch (c) {
01082           case '*':
01083           case '?':
01084           case '[':
01085             return 1;
01086 
01087           case '\\':
01088             if (escape && !(c = *p++))
01089                 return 0;
01090             continue;
01091 
01092           default:
01093             if (!FNM_SYSCASE && ISALPHA(c) && nocase)
01094                 return 1;
01095         }
01096 
01097         p = Next(p-1, pend, enc);
01098     }
01099 
01100     return 0;
01101 }
01102 
01103 /* Find separator in globbing pattern. */
01104 static char *
01105 find_dirsep(const char *p, const char *pend, int flags, rb_encoding *enc)
01106 {
01107     const int escape = !(flags & FNM_NOESCAPE);
01108 
01109     register char c;
01110     int open = 0;
01111 
01112     while ((c = *p++) != 0) {
01113         switch (c) {
01114           case '[':
01115             open = 1;
01116             continue;
01117           case ']':
01118             open = 0;
01119             continue;
01120 
01121           case '/':
01122             if (!open)
01123                 return (char *)p-1;
01124             continue;
01125 
01126           case '\\':
01127             if (escape && !(c = *p++))
01128                 return (char *)p-1;
01129             continue;
01130         }
01131 
01132         p = Next(p-1, pend, enc);
01133     }
01134 
01135     return (char *)p-1;
01136 }
01137 
01138 /* Remove escaping backslashes */
01139 static char *
01140 remove_backslashes(char *p, register const char *pend, rb_encoding *enc)
01141 {
01142     char *t = p;
01143     char *s = p;
01144 
01145     while (*p) {
01146         if (*p == '\\') {
01147             if (t != s)
01148                 memmove(t, s, p - s);
01149             t += p - s;
01150             s = ++p;
01151             if (!*p) break;
01152         }
01153         Inc(p, pend, enc);
01154     }
01155 
01156     while (*p++);
01157 
01158     if (t != s)
01159         memmove(t, s, p - s); /* move '\0' too */
01160 
01161     return p;
01162 }
01163 
01164 /* Globing pattern */
01165 enum glob_pattern_type { PLAIN, MAGICAL, RECURSIVE, MATCH_ALL, MATCH_DIR };
01166 
01167 struct glob_pattern {
01168     char *str;
01169     enum glob_pattern_type type;
01170     struct glob_pattern *next;
01171 };
01172 
01173 static void glob_free_pattern(struct glob_pattern *list);
01174 
01175 static struct glob_pattern *
01176 glob_make_pattern(const char *p, const char *e, int flags, rb_encoding *enc)
01177 {
01178     struct glob_pattern *list, *tmp, **tail = &list;
01179     int dirsep = 0; /* pattern is terminated with '/' */
01180     int recursive = 0;
01181 
01182     while (p < e && *p) {
01183         tmp = GLOB_ALLOC(struct glob_pattern);
01184         if (!tmp) goto error;
01185         if (p[0] == '*' && p[1] == '*' && p[2] == '/') {
01186             /* fold continuous RECURSIVEs (needed in glob_helper) */
01187             do { p += 3; while (*p == '/') p++; } while (p[0] == '*' && p[1] == '*' && p[2] == '/');
01188             tmp->type = RECURSIVE;
01189             tmp->str = 0;
01190             dirsep = 1;
01191             recursive = 1;
01192         }
01193         else {
01194             const char *m = find_dirsep(p, e, flags, enc);
01195             int magic = has_magic(p, m, flags, enc);
01196             char *buf;
01197 
01198             if (!magic && !recursive && *m) {
01199                 const char *m2;
01200                 while (!has_magic(m+1, m2 = find_dirsep(m+1, e, flags, enc), flags, enc) &&
01201                        *m2) {
01202                     m = m2;
01203                 }
01204             }
01205             buf = GLOB_ALLOC_N(char, m-p+1);
01206             if (!buf) {
01207                 GLOB_FREE(tmp);
01208                 goto error;
01209             }
01210             memcpy(buf, p, m-p);
01211             buf[m-p] = '\0';
01212             tmp->type = magic ? MAGICAL : PLAIN;
01213             tmp->str = buf;
01214             if (*m) {
01215                 dirsep = 1;
01216                 p = m + 1;
01217             }
01218             else {
01219                 dirsep = 0;
01220                 p = m;
01221             }
01222         }
01223         *tail = tmp;
01224         tail = &tmp->next;
01225     }
01226 
01227     tmp = GLOB_ALLOC(struct glob_pattern);
01228     if (!tmp) {
01229       error:
01230         *tail = 0;
01231         glob_free_pattern(list);
01232         return 0;
01233     }
01234     tmp->type = dirsep ? MATCH_DIR : MATCH_ALL;
01235     tmp->str = 0;
01236     *tail = tmp;
01237     tmp->next = 0;
01238 
01239     return list;
01240 }
01241 
01242 static void
01243 glob_free_pattern(struct glob_pattern *list)
01244 {
01245     while (list) {
01246         struct glob_pattern *tmp = list;
01247         list = list->next;
01248         if (tmp->str)
01249             GLOB_FREE(tmp->str);
01250         GLOB_FREE(tmp);
01251     }
01252 }
01253 
01254 static char *
01255 join_path(const char *path, int dirsep, const char *name, size_t namlen)
01256 {
01257     long len = strlen(path);
01258     char *buf = GLOB_ALLOC_N(char, len+namlen+(dirsep?1:0)+1);
01259 
01260     if (!buf) return 0;
01261     memcpy(buf, path, len);
01262     if (dirsep) {
01263         buf[len++] = '/';
01264     }
01265     memcpy(buf+len, name, namlen);
01266     buf[len+namlen] = '\0';
01267     return buf;
01268 }
01269 
01270 enum answer {UNKNOWN = -1, NO, YES};
01271 
01272 #ifndef S_ISDIR
01273 #   define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
01274 #endif
01275 
01276 #ifndef S_ISLNK
01277 #  ifndef S_IFLNK
01278 #    define S_ISLNK(m) (0)
01279 #  else
01280 #    define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
01281 #  endif
01282 #endif
01283 
01284 struct glob_args {
01285     void (*func)(const char *, VALUE, void *);
01286     const char *path;
01287     VALUE value;
01288     rb_encoding *enc;
01289 };
01290 
01291 static VALUE
01292 glob_func_caller(VALUE val)
01293 {
01294     struct glob_args *args = (struct glob_args *)val;
01295 
01296     (*args->func)(args->path, args->value, args->enc);
01297     return Qnil;
01298 }
01299 
01300 #define glob_call_func(func, path, arg, enc) (*(func))((path), (arg), (enc))
01301 
01302 static int
01303 glob_helper(
01304     const char *path,
01305     int dirsep, /* '/' should be placed before appending child entry's name to 'path'. */
01306     enum answer exist, /* Does 'path' indicate an existing entry? */
01307     enum answer isdir, /* Does 'path' indicate a directory or a symlink to a directory? */
01308     struct glob_pattern **beg,
01309     struct glob_pattern **end,
01310     int flags,
01311     ruby_glob_func *func,
01312     VALUE arg,
01313     rb_encoding *enc)
01314 {
01315     struct stat st;
01316     int status = 0;
01317     struct glob_pattern **cur, **new_beg, **new_end;
01318     int plain = 0, magical = 0, recursive = 0, match_all = 0, match_dir = 0;
01319     int escape = !(flags & FNM_NOESCAPE);
01320 
01321     for (cur = beg; cur < end; ++cur) {
01322         struct glob_pattern *p = *cur;
01323         if (p->type == RECURSIVE) {
01324             recursive = 1;
01325             p = p->next;
01326         }
01327         switch (p->type) {
01328           case PLAIN:
01329             plain = 1;
01330             break;
01331           case MAGICAL:
01332             magical = 1;
01333             break;
01334           case MATCH_ALL:
01335             match_all = 1;
01336             break;
01337           case MATCH_DIR:
01338             match_dir = 1;
01339             break;
01340           case RECURSIVE:
01341             rb_bug("continuous RECURSIVEs");
01342         }
01343     }
01344 
01345     if (*path) {
01346         if (match_all && exist == UNKNOWN) {
01347             if (do_lstat(path, &st, flags) == 0) {
01348                 exist = YES;
01349                 isdir = S_ISDIR(st.st_mode) ? YES : S_ISLNK(st.st_mode) ? UNKNOWN : NO;
01350             }
01351             else {
01352                 exist = NO;
01353                 isdir = NO;
01354             }
01355         }
01356         if (match_dir && isdir == UNKNOWN) {
01357             if (do_stat(path, &st, flags) == 0) {
01358                 exist = YES;
01359                 isdir = S_ISDIR(st.st_mode) ? YES : NO;
01360             }
01361             else {
01362                 exist = NO;
01363                 isdir = NO;
01364             }
01365         }
01366         if (match_all && exist == YES) {
01367             status = glob_call_func(func, path, arg, enc);
01368             if (status) return status;
01369         }
01370         if (match_dir && isdir == YES) {
01371             char *tmp = join_path(path, dirsep, "", 0);
01372             if (!tmp) return -1;
01373             status = glob_call_func(func, tmp, arg, enc);
01374             GLOB_FREE(tmp);
01375             if (status) return status;
01376         }
01377     }
01378 
01379     if (exist == NO || isdir == NO) return 0;
01380 
01381     if (magical || recursive) {
01382         struct dirent *dp;
01383         DIR *dirp;
01384         IF_HAVE_READDIR_R(DEFINE_STRUCT_DIRENT entry);
01385         dirp = do_opendir(*path ? path : ".", flags, enc);
01386         if (dirp == NULL) return 0;
01387 
01388         while (READDIR(dirp, enc, &STRUCT_DIRENT(entry), dp)) {
01389             char *buf;
01390             enum answer new_isdir = UNKNOWN;
01391 
01392             if (recursive && dp->d_name[0] == '.') {
01393                 /* always skip current and parent directories not to recurse infinitely */
01394                 if (!dp->d_name[1]) continue;
01395                 if (dp->d_name[1] == '.' && !dp->d_name[2]) continue;
01396             }
01397 
01398             buf = join_path(path, dirsep, dp->d_name, NAMLEN(dp));
01399             if (!buf) {
01400                 status = -1;
01401                 break;
01402             }
01403             if (recursive && ((flags & FNM_DOTMATCH) || dp->d_name[0] != '.')) {
01404                 /* RECURSIVE never match dot files unless FNM_DOTMATCH is set */
01405 #ifndef _WIN32
01406                 if (do_lstat(buf, &st, flags) == 0)
01407                     new_isdir = S_ISDIR(st.st_mode) ? YES : S_ISLNK(st.st_mode) ? UNKNOWN : NO;
01408                 else
01409                     new_isdir = NO;
01410 #else
01411                 new_isdir = dp->d_isdir ? (!dp->d_isrep ? YES : UNKNOWN) : NO;
01412 #endif
01413             }
01414 
01415             new_beg = new_end = GLOB_ALLOC_N(struct glob_pattern *, (end - beg) * 2);
01416             if (!new_beg) {
01417                 GLOB_FREE(buf);
01418                 status = -1;
01419                 break;
01420             }
01421 
01422             for (cur = beg; cur < end; ++cur) {
01423                 struct glob_pattern *p = *cur;
01424                 if (p->type == RECURSIVE) {
01425                     if (new_isdir == YES) /* not symlink but real directory */
01426                         *new_end++ = p; /* append recursive pattern */
01427                     p = p->next; /* 0 times recursion */
01428                 }
01429                 if (p->type == PLAIN || p->type == MAGICAL) {
01430                     if (fnmatch(p->str, enc, dp->d_name, flags) == 0)
01431                         *new_end++ = p->next;
01432                 }
01433             }
01434 
01435             status = glob_helper(buf, 1, YES, new_isdir, new_beg, new_end,
01436                                  flags, func, arg, enc);
01437             GLOB_FREE(buf);
01438             GLOB_FREE(new_beg);
01439             if (status) break;
01440         }
01441 
01442         closedir(dirp);
01443     }
01444     else if (plain) {
01445         struct glob_pattern **copy_beg, **copy_end, **cur2;
01446 
01447         copy_beg = copy_end = GLOB_ALLOC_N(struct glob_pattern *, end - beg);
01448         if (!copy_beg) return -1;
01449         for (cur = beg; cur < end; ++cur)
01450             *copy_end++ = (*cur)->type == PLAIN ? *cur : 0;
01451 
01452         for (cur = copy_beg; cur < copy_end; ++cur) {
01453             if (*cur) {
01454                 char *buf;
01455                 char *name;
01456                 size_t len = strlen((*cur)->str) + 1;
01457                 name = GLOB_ALLOC_N(char, len);
01458                 if (!name) {
01459                     status = -1;
01460                     break;
01461                 }
01462                 memcpy(name, (*cur)->str, len);
01463                 if (escape)
01464                     len = remove_backslashes(name, name+len-1, enc) - name;
01465 
01466                 new_beg = new_end = GLOB_ALLOC_N(struct glob_pattern *, end - beg);
01467                 if (!new_beg) {
01468                     GLOB_FREE(name);
01469                     status = -1;
01470                     break;
01471                 }
01472                 *new_end++ = (*cur)->next;
01473                 for (cur2 = cur + 1; cur2 < copy_end; ++cur2) {
01474                     if (*cur2 && fnmatch((*cur2)->str, enc, name, flags) == 0) {
01475                         *new_end++ = (*cur2)->next;
01476                         *cur2 = 0;
01477                     }
01478                 }
01479 
01480                 buf = join_path(path, dirsep, name, len);
01481                 GLOB_FREE(name);
01482                 if (!buf) {
01483                     GLOB_FREE(new_beg);
01484                     status = -1;
01485                     break;
01486                 }
01487                 status = glob_helper(buf, 1, UNKNOWN, UNKNOWN, new_beg,
01488                                      new_end, flags, func, arg, enc);
01489                 GLOB_FREE(buf);
01490                 GLOB_FREE(new_beg);
01491                 if (status) break;
01492             }
01493         }
01494 
01495         GLOB_FREE(copy_beg);
01496     }
01497 
01498     return status;
01499 }
01500 
01501 static int
01502 ruby_glob0(const char *path, int flags, ruby_glob_func *func, VALUE arg, rb_encoding *enc)
01503 {
01504     struct glob_pattern *list;
01505     const char *root, *start;
01506     char *buf;
01507     size_t n;
01508     int status;
01509 
01510     start = root = path;
01511     flags |= FNM_SYSCASE;
01512 #if defined DOSISH
01513     root = rb_enc_path_skip_prefix(root, root + strlen(root), enc);
01514 #endif
01515 
01516     if (root && *root == '/') root++;
01517 
01518     n = root - start;
01519     buf = GLOB_ALLOC_N(char, n + 1);
01520     if (!buf) return -1;
01521     MEMCPY(buf, start, char, n);
01522     buf[n] = '\0';
01523 
01524     list = glob_make_pattern(root, root + strlen(root), flags, enc);
01525     if (!list) {
01526         GLOB_FREE(buf);
01527         return -1;
01528     }
01529     status = glob_helper(buf, 0, UNKNOWN, UNKNOWN, &list, &list + 1, flags, func, arg, enc);
01530     glob_free_pattern(list);
01531     GLOB_FREE(buf);
01532 
01533     return status;
01534 }
01535 
01536 int
01537 ruby_glob(const char *path, int flags, ruby_glob_func *func, VALUE arg)
01538 {
01539     return ruby_glob0(path, flags & ~GLOB_VERBOSE, func, arg,
01540                       rb_ascii8bit_encoding());
01541 }
01542 
01543 static int
01544 rb_glob_caller(const char *path, VALUE a, void *enc)
01545 {
01546     int status;
01547     struct glob_args *args = (struct glob_args *)a;
01548 
01549     args->path = path;
01550     rb_protect(glob_func_caller, a, &status);
01551     return status;
01552 }
01553 
01554 static int
01555 rb_glob2(const char *path, int flags,
01556          void (*func)(const char *, VALUE, void *), VALUE arg,
01557          rb_encoding* enc)
01558 {
01559     struct glob_args args;
01560 
01561     args.func = func;
01562     args.value = arg;
01563     args.enc = enc;
01564 
01565     if (flags & FNM_SYSCASE) {
01566         rb_warning("Dir.glob() ignores File::FNM_CASEFOLD");
01567     }
01568 
01569     return ruby_glob0(path, flags | GLOB_VERBOSE, rb_glob_caller, (VALUE)&args,
01570                       enc);
01571 }
01572 
01573 void
01574 rb_glob(const char *path, void (*func)(const char *, VALUE, void *), VALUE arg)
01575 {
01576     int status = rb_glob2(path, 0, func, arg, rb_ascii8bit_encoding());
01577     if (status) GLOB_JUMP_TAG(status);
01578 }
01579 
01580 static void
01581 push_pattern(const char *path, VALUE ary, void *enc)
01582 {
01583     rb_ary_push(ary, rb_external_str_new_with_enc(path, strlen(path), enc));
01584 }
01585 
01586 static int
01587 ruby_brace_expand(const char *str, int flags, ruby_glob_func *func, VALUE arg,
01588                   rb_encoding *enc)
01589 {
01590     const int escape = !(flags & FNM_NOESCAPE);
01591     const char *p = str;
01592     const char *pend = p + strlen(p);
01593     const char *s = p;
01594     const char *lbrace = 0, *rbrace = 0;
01595     int nest = 0, status = 0;
01596 
01597     while (*p) {
01598         if (*p == '{' && nest++ == 0) {
01599             lbrace = p;
01600         }
01601         if (*p == '}' && --nest <= 0) {
01602             rbrace = p;
01603             break;
01604         }
01605         if (*p == '\\' && escape) {
01606             if (!*++p) break;
01607         }
01608         Inc(p, pend, enc);
01609     }
01610 
01611     if (lbrace && rbrace) {
01612         size_t len = strlen(s) + 1;
01613         char *buf = GLOB_ALLOC_N(char, len);
01614         long shift;
01615 
01616         if (!buf) return -1;
01617         memcpy(buf, s, lbrace-s);
01618         shift = (lbrace-s);
01619         p = lbrace;
01620         while (p < rbrace) {
01621             const char *t = ++p;
01622             nest = 0;
01623             while (p < rbrace && !(*p == ',' && nest == 0)) {
01624                 if (*p == '{') nest++;
01625                 if (*p == '}') nest--;
01626                 if (*p == '\\' && escape) {
01627                     if (++p == rbrace) break;
01628                 }
01629                 Inc(p, pend, enc);
01630             }
01631             memcpy(buf+shift, t, p-t);
01632             strlcpy(buf+shift+(p-t), rbrace+1, len-(shift+(p-t)));
01633             status = ruby_brace_expand(buf, flags, func, arg, enc);
01634             if (status) break;
01635         }
01636         GLOB_FREE(buf);
01637     }
01638     else if (!lbrace && !rbrace) {
01639         status = (*func)(s, arg, enc);
01640     }
01641 
01642     return status;
01643 }
01644 
01645 struct brace_args {
01646     ruby_glob_func *func;
01647     VALUE value;
01648     int flags;
01649 };
01650 
01651 static int
01652 glob_brace(const char *path, VALUE val, void *enc)
01653 {
01654     struct brace_args *arg = (struct brace_args *)val;
01655 
01656     return ruby_glob0(path, arg->flags, arg->func, arg->value, enc);
01657 }
01658 
01659 static int
01660 ruby_brace_glob0(const char *str, int flags, ruby_glob_func *func, VALUE arg,
01661                  rb_encoding* enc)
01662 {
01663     struct brace_args args;
01664 
01665     args.func = func;
01666     args.value = arg;
01667     args.flags = flags;
01668     return ruby_brace_expand(str, flags, glob_brace, (VALUE)&args, enc);
01669 }
01670 
01671 int
01672 ruby_brace_glob(const char *str, int flags, ruby_glob_func *func, VALUE arg)
01673 {
01674     return ruby_brace_glob0(str, flags & ~GLOB_VERBOSE, func, arg,
01675                             rb_ascii8bit_encoding());
01676 }
01677 
01678 int
01679 ruby_brace_glob_with_enc(const char *str, int flags, ruby_glob_func *func, VALUE arg, rb_encoding *enc)
01680 {
01681     return ruby_brace_glob0(str, flags & ~GLOB_VERBOSE, func, arg, enc);
01682 }
01683 
01684 static int
01685 push_glob(VALUE ary, VALUE str, int flags)
01686 {
01687     struct glob_args args;
01688     rb_encoding *enc = rb_enc_get(str);
01689 
01690     if (enc == rb_usascii_encoding()) enc = rb_filesystem_encoding();
01691     args.func = push_pattern;
01692     args.value = ary;
01693     args.enc = enc;
01694 
01695     RB_GC_GUARD(str);
01696     return ruby_brace_glob0(RSTRING_PTR(str), flags | GLOB_VERBOSE,
01697                             rb_glob_caller, (VALUE)&args, enc);
01698 }
01699 
01700 static VALUE
01701 rb_push_glob(VALUE str, int flags) /* '\0' is delimiter */
01702 {
01703     long offset = 0;
01704     VALUE ary;
01705 
01706     GlobPathValue(str, TRUE);
01707     ary = rb_ary_new();
01708 
01709     while (offset < RSTRING_LEN(str)) {
01710         char *p, *pend;
01711         int status;
01712         p = RSTRING_PTR(str) + offset;
01713         status = push_glob(ary, rb_enc_str_new(p, strlen(p), rb_enc_get(str)),
01714                            flags);
01715         if (status) GLOB_JUMP_TAG(status);
01716         if (offset >= RSTRING_LEN(str)) break;
01717         p += strlen(p) + 1;
01718         pend = RSTRING_PTR(str) + RSTRING_LEN(str);
01719         while (p < pend && !*p)
01720             p++;
01721         offset = p - RSTRING_PTR(str);
01722     }
01723 
01724     return ary;
01725 }
01726 
01727 static VALUE
01728 dir_globs(long argc, VALUE *argv, int flags)
01729 {
01730     VALUE ary = rb_ary_new();
01731     long i;
01732 
01733     for (i = 0; i < argc; ++i) {
01734         int status;
01735         VALUE str = argv[i];
01736         GlobPathValue(str, TRUE);
01737         status = push_glob(ary, str, flags);
01738         if (status) GLOB_JUMP_TAG(status);
01739     }
01740 
01741     return ary;
01742 }
01743 
01744 /*
01745  *  call-seq:
01746  *     Dir[ array ]                 -> array
01747  *     Dir[ string [, string ...] ] -> array
01748  *
01749  *  Equivalent to calling
01750  *  <code>Dir.glob(</code><i>array,</i><code>0)</code> and
01751  *  <code>Dir.glob([</code><i>string,...</i><code>],0)</code>.
01752  *
01753  */
01754 static VALUE
01755 dir_s_aref(int argc, VALUE *argv, VALUE obj)
01756 {
01757     if (argc == 1) {
01758         return rb_push_glob(argv[0], 0);
01759     }
01760     return dir_globs(argc, argv, 0);
01761 }
01762 
01763 /*
01764  *  call-seq:
01765  *     Dir.glob( pattern, [flags] ) -> array
01766  *     Dir.glob( pattern, [flags] ) {| filename | block }  -> nil
01767  *
01768  *  Returns the filenames found by expanding <i>pattern</i> which is
01769  *  an +Array+ of the patterns or the pattern +String+, either as an
01770  *  <i>array</i> or as parameters to the block. Note that this pattern
01771  *  is not a regexp (it's closer to a shell glob). See
01772  *  <code>File::fnmatch</code> for the meaning of the <i>flags</i>
01773  *  parameter. Note that case sensitivity depends on your system (so
01774  *  <code>File::FNM_CASEFOLD</code> is ignored), as does the order
01775  *  in which the results are returned.
01776  *
01777  *  <code>*</code>::        Matches any file. Can be restricted by
01778  *                          other values in the glob. <code>*</code>
01779  *                          will match all files; <code>c*</code> will
01780  *                          match all files beginning with
01781  *                          <code>c</code>; <code>*c</code> will match
01782  *                          all files ending with <code>c</code>; and
01783  *                          <code>\*c\*</code> will match all files that
01784  *                          have <code>c</code> in them (including at
01785  *                          the beginning or end). Equivalent to
01786  *                          <code>/ .* /x</code> in regexp. Note, this
01787  *                          will not match Unix-like hidden files (dotfiles).
01788  *                          In order to include those in the match results,
01789  *                          you must use something like <code>"{*,.*}"</code>.
01790  *  <code>**</code>::       Matches directories recursively.
01791  *  <code>?</code>::        Matches any one character. Equivalent to
01792  *                          <code>/.{1}/</code> in regexp.
01793  *  <code>[set]</code>::    Matches any one character in +set+.
01794  *                          Behaves exactly like character sets in
01795  *                          Regexp, including set negation
01796  *                          (<code>[^a-z]</code>).
01797  *  <code>{p,q}</code>::    Matches either literal <code>p</code> or
01798  *                          literal <code>q</code>. Matching literals
01799  *                          may be more than one character in length.
01800  *                          More than two literals may be specified.
01801  *                          Equivalent to pattern alternation in
01802  *                          regexp.
01803  *  <code> \\ </code>::     Escapes the next metacharacter.
01804  *                          Note that this means you cannot use backslash
01805  *                          in windows as part of a glob,
01806  *                          i.e. <code>Dir["c:\\foo*"]</code> will not work,
01807  *                          use <code>Dir["c:/foo*"]</code> instead.
01808  *
01809  *     Dir["config.?"]                     #=> ["config.h"]
01810  *     Dir.glob("config.?")                #=> ["config.h"]
01811  *     Dir.glob("*.[a-z][a-z]")            #=> ["main.rb"]
01812  *     Dir.glob("*.[^r]*")                 #=> ["config.h"]
01813  *     Dir.glob("*.{rb,h}")                #=> ["main.rb", "config.h"]
01814  *     Dir.glob("*")                       #=> ["config.h", "main.rb"]
01815  *     Dir.glob("*", File::FNM_DOTMATCH)   #=> [".", "..", "config.h", "main.rb"]
01816  *
01817  *     rbfiles = File.join("**", "*.rb")
01818  *     Dir.glob(rbfiles)                   #=> ["main.rb",
01819  *                                         #    "lib/song.rb",
01820  *                                         #    "lib/song/karaoke.rb"]
01821  *     libdirs = File.join("**", "lib")
01822  *     Dir.glob(libdirs)                   #=> ["lib"]
01823  *
01824  *     librbfiles = File.join("**", "lib", "**", "*.rb")
01825  *     Dir.glob(librbfiles)                #=> ["lib/song.rb",
01826  *                                         #    "lib/song/karaoke.rb"]
01827  *
01828  *     librbfiles = File.join("**", "lib", "*.rb")
01829  *     Dir.glob(librbfiles)                #=> ["lib/song.rb"]
01830  */
01831 static VALUE
01832 dir_s_glob(int argc, VALUE *argv, VALUE obj)
01833 {
01834     VALUE str, rflags, ary;
01835     int flags;
01836 
01837     if (rb_scan_args(argc, argv, "11", &str, &rflags) == 2)
01838         flags = NUM2INT(rflags);
01839     else
01840         flags = 0;
01841 
01842     ary = rb_check_array_type(str);
01843     if (NIL_P(ary)) {
01844         ary = rb_push_glob(str, flags);
01845     }
01846     else {
01847         volatile VALUE v = ary;
01848         ary = dir_globs(RARRAY_LEN(v), RARRAY_PTR(v), flags);
01849     }
01850 
01851     if (rb_block_given_p()) {
01852         rb_ary_each(ary);
01853         return Qnil;
01854     }
01855     return ary;
01856 }
01857 
01858 static VALUE
01859 dir_open_dir(int argc, VALUE *argv)
01860 {
01861     VALUE dir = rb_funcall2(rb_cDir, rb_intern("open"), argc, argv);
01862 
01863     rb_check_typeddata(dir, &dir_data_type);
01864     return dir;
01865 }
01866 
01867 
01868 /*
01869  *  call-seq:
01870  *     Dir.foreach( dirname ) {| filename | block }  -> nil
01871  *     Dir.foreach( dirname )                        -> an_enumerator
01872  *
01873  *  Calls the block once for each entry in the named directory, passing
01874  *  the filename of each entry as a parameter to the block.
01875  *
01876  *  If no block is given, an enumerator is returned instead.
01877  *
01878  *     Dir.foreach("testdir") {|x| puts "Got #{x}" }
01879  *
01880  *  <em>produces:</em>
01881  *
01882  *     Got .
01883  *     Got ..
01884  *     Got config.h
01885  *     Got main.rb
01886  *
01887  */
01888 static VALUE
01889 dir_foreach(int argc, VALUE *argv, VALUE io)
01890 {
01891     VALUE dir;
01892 
01893     RETURN_ENUMERATOR(io, argc, argv);
01894     dir = dir_open_dir(argc, argv);
01895     rb_ensure(dir_each, dir, dir_close, dir);
01896     return Qnil;
01897 }
01898 
01899 /*
01900  *  call-seq:
01901  *     Dir.entries( dirname ) -> array
01902  *
01903  *  Returns an array containing all of the filenames in the given
01904  *  directory. Will raise a <code>SystemCallError</code> if the named
01905  *  directory doesn't exist.
01906  *
01907  *     Dir.entries("testdir")   #=> [".", "..", "config.h", "main.rb"]
01908  *
01909  */
01910 static VALUE
01911 dir_entries(int argc, VALUE *argv, VALUE io)
01912 {
01913     VALUE dir;
01914 
01915     dir = dir_open_dir(argc, argv);
01916     return rb_ensure(rb_Array, dir, dir_close, dir);
01917 }
01918 
01919 static int
01920 fnmatch_brace(const char *pattern, VALUE val, void *enc)
01921 {
01922     struct brace_args *arg = (struct brace_args *)val;
01923     VALUE path = arg->value;
01924     rb_encoding *enc_pattern = enc;
01925     rb_encoding *enc_path = rb_enc_get(path);
01926 
01927     if (enc_pattern != enc_path) {
01928         if (!rb_enc_asciicompat(enc_pattern))
01929             return FNM_NOMATCH;
01930         if (!rb_enc_asciicompat(enc_path))
01931             return FNM_NOMATCH;
01932         if (!rb_enc_str_asciionly_p(path)) {
01933             int cr = ENC_CODERANGE_7BIT;
01934             long len = strlen(pattern);
01935             if (rb_str_coderange_scan_restartable(pattern, pattern + len,
01936                                                   enc_pattern, &cr) != len)
01937                 return FNM_NOMATCH;
01938             if (cr != ENC_CODERANGE_7BIT)
01939                 return FNM_NOMATCH;
01940         }
01941     }
01942     return (fnmatch(pattern, enc, RSTRING_PTR(path), arg->flags) == 0);
01943 }
01944 
01945 /*
01946  *  call-seq:
01947  *     File.fnmatch( pattern, path, [flags] ) -> (true or false)
01948  *     File.fnmatch?( pattern, path, [flags] ) -> (true or false)
01949  *
01950  *  Returns true if <i>path</i> matches against <i>pattern</i> The
01951  *  pattern is not a regular expression; instead it follows rules
01952  *  similar to shell filename globbing. It may contain the following
01953  *  metacharacters:
01954  *
01955  *  <code>*</code>::        Matches any file. Can be restricted by
01956  *                          other values in the glob. <code>*</code>
01957  *                          will match all files; <code>c*</code> will
01958  *                          match all files beginning with
01959  *                          <code>c</code>; <code>*c</code> will match
01960  *                          all files ending with <code>c</code>; and
01961  *                          <code>\*c*</code> will match all files that
01962  *                          have <code>c</code> in them (including at
01963  *                          the beginning or end). Equivalent to
01964  *                          <code>/ .* /x</code> in regexp.
01965  *  <code>**</code>::       Matches directories recursively or files
01966  *                          expansively.
01967  *  <code>?</code>::        Matches any one character. Equivalent to
01968  *                          <code>/.{1}/</code> in regexp.
01969  *  <code>[set]</code>::    Matches any one character in +set+.
01970  *                          Behaves exactly like character sets in
01971  *                          Regexp, including set negation
01972  *                          (<code>[^a-z]</code>).
01973  *  <code> \ </code>::      Escapes the next metacharacter.
01974  *
01975  *  <i>flags</i> is a bitwise OR of the <code>FNM_xxx</code>
01976  *  parameters. The same glob pattern and flags are used by
01977  *  <code>Dir::glob</code>.
01978  *
01979  *     File.fnmatch('cat',       'cat')        #=> true  # match entire string
01980  *     File.fnmatch('cat',       'category')   #=> false # only match partial string
01981  *     File.fnmatch('c{at,ub}s', 'cats')       #=> false # { } isn't supported
01982  *
01983  *     File.fnmatch('c?t',     'cat')          #=> true  # '?' match only 1 character
01984  *     File.fnmatch('c??t',    'cat')          #=> false # ditto
01985  *     File.fnmatch('c*',      'cats')         #=> true  # '*' match 0 or more characters
01986  *     File.fnmatch('c*t',     'c/a/b/t')      #=> true  # ditto
01987  *     File.fnmatch('ca[a-z]', 'cat')          #=> true  # inclusive bracket expression
01988  *     File.fnmatch('ca[^t]',  'cat')          #=> false # exclusive bracket expression ('^' or '!')
01989  *
01990  *     File.fnmatch('cat', 'CAT')                     #=> false # case sensitive
01991  *     File.fnmatch('cat', 'CAT', File::FNM_CASEFOLD) #=> true  # case insensitive
01992  *
01993  *     File.fnmatch('?',   '/', File::FNM_PATHNAME)  #=> false # wildcard doesn't match '/' on FNM_PATHNAME
01994  *     File.fnmatch('*',   '/', File::FNM_PATHNAME)  #=> false # ditto
01995  *     File.fnmatch('[/]', '/', File::FNM_PATHNAME)  #=> false # ditto
01996  *
01997  *     File.fnmatch('\?',   '?')                       #=> true  # escaped wildcard becomes ordinary
01998  *     File.fnmatch('\a',   'a')                       #=> true  # escaped ordinary remains ordinary
01999  *     File.fnmatch('\a',   '\a', File::FNM_NOESCAPE)  #=> true  # FNM_NOESCAPE makes '\' ordinary
02000  *     File.fnmatch('[\?]', '?')                       #=> true  # can escape inside bracket expression
02001  *
02002  *     File.fnmatch('*',   '.profile')                      #=> false # wildcard doesn't match leading
02003  *     File.fnmatch('*',   '.profile', File::FNM_DOTMATCH)  #=> true  # period by default.
02004  *     File.fnmatch('.*',  '.profile')                      #=> true
02005  *
02006  *     rbfiles = '**' '/' '*.rb' # you don't have to do like this. just write in single string.
02007  *     File.fnmatch(rbfiles, 'main.rb')                    #=> false
02008  *     File.fnmatch(rbfiles, './main.rb')                  #=> false
02009  *     File.fnmatch(rbfiles, 'lib/song.rb')                #=> true
02010  *     File.fnmatch('**.rb', 'main.rb')                    #=> true
02011  *     File.fnmatch('**.rb', './main.rb')                  #=> false
02012  *     File.fnmatch('**.rb', 'lib/song.rb')                #=> true
02013  *     File.fnmatch('*',           'dave/.profile')                      #=> true
02014  *
02015  *     pattern = '*' '/' '*'
02016  *     File.fnmatch(pattern, 'dave/.profile', File::FNM_PATHNAME)  #=> false
02017  *     File.fnmatch(pattern, 'dave/.profile', File::FNM_PATHNAME | File::FNM_DOTMATCH) #=> true
02018  *
02019  *     pattern = '**' '/' 'foo'
02020  *     File.fnmatch(pattern, 'a/b/c/foo', File::FNM_PATHNAME)     #=> true
02021  *     File.fnmatch(pattern, '/a/b/c/foo', File::FNM_PATHNAME)    #=> true
02022  *     File.fnmatch(pattern, 'c:/a/b/c/foo', File::FNM_PATHNAME)  #=> true
02023  *     File.fnmatch(pattern, 'a/.b/c/foo', File::FNM_PATHNAME)    #=> false
02024  *     File.fnmatch(pattern, 'a/.b/c/foo', File::FNM_PATHNAME | File::FNM_DOTMATCH) #=> true
02025  */
02026 static VALUE
02027 file_s_fnmatch(int argc, VALUE *argv, VALUE obj)
02028 {
02029     VALUE pattern, path;
02030     VALUE rflags;
02031     int flags;
02032 
02033     if (rb_scan_args(argc, argv, "21", &pattern, &path, &rflags) == 3)
02034         flags = NUM2INT(rflags);
02035     else
02036         flags = 0;
02037 
02038     StringValue(pattern);
02039     FilePathStringValue(path);
02040 
02041     if (flags & FNM_EXTGLOB) {
02042         struct brace_args args;
02043 
02044         args.value = path;
02045         args.flags = flags;
02046         if (ruby_brace_expand(RSTRING_PTR(pattern), flags, fnmatch_brace,
02047                               (VALUE)&args, rb_enc_get(pattern)) > 0)
02048             return Qtrue;
02049     }
02050     else {
02051         rb_encoding *enc = rb_enc_compatible(pattern, path);
02052         if (!enc) return Qfalse;
02053         if (fnmatch(RSTRING_PTR(pattern), enc, RSTRING_PTR(path), flags) == 0)
02054             return Qtrue;
02055     }
02056     RB_GC_GUARD(pattern);
02057 
02058     return Qfalse;
02059 }
02060 
02061 /*
02062  *  call-seq:
02063  *    Dir.home()       -> "/home/me"
02064  *    Dir.home("root") -> "/root"
02065  *
02066  *  Returns the home directory of the current user or the named user
02067  *  if given.
02068  */
02069 static VALUE
02070 dir_s_home(int argc, VALUE *argv, VALUE obj)
02071 {
02072     VALUE user;
02073     const char *u = 0;
02074 
02075     rb_scan_args(argc, argv, "01", &user);
02076     if (!NIL_P(user)) {
02077         SafeStringValue(user);
02078         u = StringValueCStr(user);
02079     }
02080     return rb_home_dir(u, rb_str_new(0, 0));
02081 }
02082 
02083 #if 0
02084 /*
02085  * call-seq:
02086  *   Dir.exist?(file_name)   ->  true or false
02087  *   Dir.exists?(file_name)   ->  true or false
02088  *
02089  * Returns <code>true</code> if the named file is a directory,
02090  * <code>false</code> otherwise.
02091  *
02092  */
02093 VALUE
02094 rb_file_directory_p()
02095 {
02096 }
02097 #endif
02098 
02099 /*
02100  *  Objects of class <code>Dir</code> are directory streams representing
02101  *  directories in the underlying file system. They provide a variety of
02102  *  ways to list directories and their contents. See also
02103  *  <code>File</code>.
02104  *
02105  *  The directory used in these examples contains the two regular files
02106  *  (<code>config.h</code> and <code>main.rb</code>), the parent
02107  *  directory (<code>..</code>), and the directory itself
02108  *  (<code>.</code>).
02109  */
02110 void
02111 Init_Dir(void)
02112 {
02113     rb_cDir = rb_define_class("Dir", rb_cObject);
02114 
02115     rb_include_module(rb_cDir, rb_mEnumerable);
02116 
02117     rb_define_alloc_func(rb_cDir, dir_s_alloc);
02118     rb_define_singleton_method(rb_cDir, "open", dir_s_open, -1);
02119     rb_define_singleton_method(rb_cDir, "foreach", dir_foreach, -1);
02120     rb_define_singleton_method(rb_cDir, "entries", dir_entries, -1);
02121 
02122     rb_define_method(rb_cDir,"initialize", dir_initialize, -1);
02123     rb_define_method(rb_cDir,"path", dir_path, 0);
02124     rb_define_method(rb_cDir,"to_path", dir_path, 0);
02125     rb_define_method(rb_cDir,"inspect", dir_inspect, 0);
02126     rb_define_method(rb_cDir,"read", dir_read, 0);
02127     rb_define_method(rb_cDir,"each", dir_each, 0);
02128     rb_define_method(rb_cDir,"rewind", dir_rewind, 0);
02129     rb_define_method(rb_cDir,"tell", dir_tell, 0);
02130     rb_define_method(rb_cDir,"seek", dir_seek, 1);
02131     rb_define_method(rb_cDir,"pos", dir_tell, 0);
02132     rb_define_method(rb_cDir,"pos=", dir_set_pos, 1);
02133     rb_define_method(rb_cDir,"close", dir_close, 0);
02134 
02135     rb_define_singleton_method(rb_cDir,"chdir", dir_s_chdir, -1);
02136     rb_define_singleton_method(rb_cDir,"getwd", dir_s_getwd, 0);
02137     rb_define_singleton_method(rb_cDir,"pwd", dir_s_getwd, 0);
02138     rb_define_singleton_method(rb_cDir,"chroot", dir_s_chroot, 1);
02139     rb_define_singleton_method(rb_cDir,"mkdir", dir_s_mkdir, -1);
02140     rb_define_singleton_method(rb_cDir,"rmdir", dir_s_rmdir, 1);
02141     rb_define_singleton_method(rb_cDir,"delete", dir_s_rmdir, 1);
02142     rb_define_singleton_method(rb_cDir,"unlink", dir_s_rmdir, 1);
02143     rb_define_singleton_method(rb_cDir,"home", dir_s_home, -1);
02144 
02145     rb_define_singleton_method(rb_cDir,"glob", dir_s_glob, -1);
02146     rb_define_singleton_method(rb_cDir,"[]", dir_s_aref, -1);
02147     rb_define_singleton_method(rb_cDir,"exist?", rb_file_directory_p, 1);
02148     rb_define_singleton_method(rb_cDir,"exists?", rb_file_directory_p, 1);
02149 
02150     rb_define_singleton_method(rb_cFile,"fnmatch", file_s_fnmatch, -1);
02151     rb_define_singleton_method(rb_cFile,"fnmatch?", file_s_fnmatch, -1);
02152 
02153     rb_file_const("FNM_NOESCAPE", INT2FIX(FNM_NOESCAPE));
02154     rb_file_const("FNM_PATHNAME", INT2FIX(FNM_PATHNAME));
02155     rb_file_const("FNM_DOTMATCH", INT2FIX(FNM_DOTMATCH));
02156     rb_file_const("FNM_CASEFOLD", INT2FIX(FNM_CASEFOLD));
02157     rb_file_const("FNM_EXTGLOB", INT2FIX(FNM_EXTGLOB));
02158     rb_file_const("FNM_SYSCASE", INT2FIX(FNM_SYSCASE));
02159 }
02160