Ruby  1.9.3p286(2012-10-12revision37165)
dir.c
Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   dir.c -
00004 
00005   $Author: naruse $
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 # if !defined __NeXT__
00034 #  define NAMLEN(dirent) (dirent)->d_namlen
00035 # else
00036 #  /* On some versions of NextStep, d_namlen is always zero, so avoid it. */
00037 #  define NAMLEN(dirent) strlen((dirent)->d_name)
00038 # endif
00039 # if HAVE_SYS_NDIR_H
00040 #  include <sys/ndir.h>
00041 # endif
00042 # if HAVE_SYS_DIR_H
00043 #  include <sys/dir.h>
00044 # endif
00045 # if HAVE_NDIR_H
00046 #  include <ndir.h>
00047 # endif
00048 # ifdef _WIN32
00049 #  include "win32/dir.h"
00050 # endif
00051 #endif
00052 
00053 #include <errno.h>
00054 
00055 #ifndef HAVE_STDLIB_H
00056 char *getenv();
00057 #endif
00058 
00059 #ifndef HAVE_STRING_H
00060 char *strchr(char*,char);
00061 #endif
00062 
00063 #include <ctype.h>
00064 
00065 #include "ruby/util.h"
00066 
00067 #if !defined HAVE_LSTAT && !defined lstat
00068 #define lstat stat
00069 #endif
00070 
00071 /* define system APIs */
00072 #ifdef _WIN32
00073 #undef chdir
00074 #define chdir(p) rb_w32_uchdir(p)
00075 #undef mkdir
00076 #define mkdir(p, m) rb_w32_umkdir((p), (m))
00077 #undef rmdir
00078 #define rmdir(p) rb_w32_urmdir(p)
00079 #undef opendir
00080 #define opendir(p) rb_w32_uopendir(p)
00081 #endif
00082 
00083 #define rb_sys_fail_path(path) rb_sys_fail_str(path)
00084 
00085 #define FNM_NOESCAPE    0x01
00086 #define FNM_PATHNAME    0x02
00087 #define FNM_DOTMATCH    0x04
00088 #define FNM_CASEFOLD    0x08
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, r) == 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     argc = 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_with_enc((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 if (errno == 0) {      /* end of stream */
00593         return Qnil;
00594     }
00595     else {
00596         rb_sys_fail(0);
00597     }
00598     return Qnil;                /* not reached */
00599 }
00600 
00601 /*
00602  *  call-seq:
00603  *     dir.each { |filename| block }  -> dir
00604  *     dir.each                       -> an_enumerator
00605  *
00606  *  Calls the block once for each entry in this directory, passing the
00607  *  filename of each entry as a parameter to the block.
00608  *
00609  *  If no block is given, an enumerator is returned instead.
00610  *
00611  *     d = Dir.new("testdir")
00612  *     d.each  {|x| puts "Got #{x}" }
00613  *
00614  *  <em>produces:</em>
00615  *
00616  *     Got .
00617  *     Got ..
00618  *     Got config.h
00619  *     Got main.rb
00620  */
00621 static VALUE
00622 dir_each(VALUE dir)
00623 {
00624     struct dir_data *dirp;
00625     struct dirent *dp;
00626     IF_HAVE_READDIR_R(DEFINE_STRUCT_DIRENT entry);
00627 
00628     RETURN_ENUMERATOR(dir, 0, 0);
00629     GetDIR(dir, dirp);
00630     rewinddir(dirp->dir);
00631     while (READDIR(dirp->dir, dirp->enc, &STRUCT_DIRENT(entry), dp)) {
00632         rb_yield(rb_external_str_new_with_enc(dp->d_name, NAMLEN(dp), dirp->enc));
00633         if (dirp->dir == NULL) dir_closed();
00634     }
00635     return dir;
00636 }
00637 
00638 #ifdef HAVE_TELLDIR
00639 /*
00640  *  call-seq:
00641  *     dir.pos -> integer
00642  *     dir.tell -> integer
00643  *
00644  *  Returns the current position in <em>dir</em>. See also
00645  *  <code>Dir#seek</code>.
00646  *
00647  *     d = Dir.new("testdir")
00648  *     d.tell   #=> 0
00649  *     d.read   #=> "."
00650  *     d.tell   #=> 12
00651  */
00652 static VALUE
00653 dir_tell(VALUE dir)
00654 {
00655     struct dir_data *dirp;
00656     long pos;
00657 
00658     GetDIR(dir, dirp);
00659     pos = telldir(dirp->dir);
00660     return rb_int2inum(pos);
00661 }
00662 #else
00663 #define dir_tell rb_f_notimplement
00664 #endif
00665 
00666 #ifdef HAVE_SEEKDIR
00667 /*
00668  *  call-seq:
00669  *     dir.seek( integer ) -> dir
00670  *
00671  *  Seeks to a particular location in <em>dir</em>. <i>integer</i>
00672  *  must be a value returned by <code>Dir#tell</code>.
00673  *
00674  *     d = Dir.new("testdir")   #=> #<Dir:0x401b3c40>
00675  *     d.read                   #=> "."
00676  *     i = d.tell               #=> 12
00677  *     d.read                   #=> ".."
00678  *     d.seek(i)                #=> #<Dir:0x401b3c40>
00679  *     d.read                   #=> ".."
00680  */
00681 static VALUE
00682 dir_seek(VALUE dir, VALUE pos)
00683 {
00684     struct dir_data *dirp;
00685     long p = NUM2LONG(pos);
00686 
00687     GetDIR(dir, dirp);
00688     seekdir(dirp->dir, p);
00689     return dir;
00690 }
00691 #else
00692 #define dir_seek rb_f_notimplement
00693 #endif
00694 
00695 /*
00696  *  call-seq:
00697  *     dir.pos( integer ) -> integer
00698  *
00699  *  Synonym for <code>Dir#seek</code>, but returns the position
00700  *  parameter.
00701  *
00702  *     d = Dir.new("testdir")   #=> #<Dir:0x401b3c40>
00703  *     d.read                   #=> "."
00704  *     i = d.pos                #=> 12
00705  *     d.read                   #=> ".."
00706  *     d.pos = i                #=> 12
00707  *     d.read                   #=> ".."
00708  */
00709 static VALUE
00710 dir_set_pos(VALUE dir, VALUE pos)
00711 {
00712     dir_seek(dir, pos);
00713     return pos;
00714 }
00715 
00716 /*
00717  *  call-seq:
00718  *     dir.rewind -> dir
00719  *
00720  *  Repositions <em>dir</em> to the first entry.
00721  *
00722  *     d = Dir.new("testdir")
00723  *     d.read     #=> "."
00724  *     d.rewind   #=> #<Dir:0x401b3fb0>
00725  *     d.read     #=> "."
00726  */
00727 static VALUE
00728 dir_rewind(VALUE dir)
00729 {
00730     struct dir_data *dirp;
00731 
00732     if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(dir)) {
00733         rb_raise(rb_eSecurityError, "Insecure: can't close");
00734     }
00735     GetDIR(dir, dirp);
00736     rewinddir(dirp->dir);
00737     return dir;
00738 }
00739 
00740 /*
00741  *  call-seq:
00742  *     dir.close -> nil
00743  *
00744  *  Closes the directory stream. Any further attempts to access
00745  *  <em>dir</em> will raise an <code>IOError</code>.
00746  *
00747  *     d = Dir.new("testdir")
00748  *     d.close   #=> nil
00749  */
00750 static VALUE
00751 dir_close(VALUE dir)
00752 {
00753     struct dir_data *dirp;
00754 
00755     GetDIR(dir, dirp);
00756     closedir(dirp->dir);
00757     dirp->dir = NULL;
00758 
00759     return Qnil;
00760 }
00761 
00762 static void
00763 dir_chdir(VALUE path)
00764 {
00765     if (chdir(RSTRING_PTR(path)) < 0)
00766         rb_sys_fail_path(path);
00767 }
00768 
00769 static int chdir_blocking = 0;
00770 static VALUE chdir_thread = Qnil;
00771 
00772 struct chdir_data {
00773     VALUE old_path, new_path;
00774     int done;
00775 };
00776 
00777 static VALUE
00778 chdir_yield(struct chdir_data *args)
00779 {
00780     dir_chdir(args->new_path);
00781     args->done = TRUE;
00782     chdir_blocking++;
00783     if (chdir_thread == Qnil)
00784         chdir_thread = rb_thread_current();
00785     return rb_yield(args->new_path);
00786 }
00787 
00788 static VALUE
00789 chdir_restore(struct chdir_data *args)
00790 {
00791     if (args->done) {
00792         chdir_blocking--;
00793         if (chdir_blocking == 0)
00794             chdir_thread = Qnil;
00795         dir_chdir(args->old_path);
00796     }
00797     return Qnil;
00798 }
00799 
00800 /*
00801  *  call-seq:
00802  *     Dir.chdir( [ string] ) -> 0
00803  *     Dir.chdir( [ string] ) {| path | block }  -> anObject
00804  *
00805  *  Changes the current working directory of the process to the given
00806  *  string. When called without an argument, changes the directory to
00807  *  the value of the environment variable <code>HOME</code>, or
00808  *  <code>LOGDIR</code>. <code>SystemCallError</code> (probably
00809  *  <code>Errno::ENOENT</code>) if the target directory does not exist.
00810  *
00811  *  If a block is given, it is passed the name of the new current
00812  *  directory, and the block is executed with that as the current
00813  *  directory. The original working directory is restored when the block
00814  *  exits. The return value of <code>chdir</code> is the value of the
00815  *  block. <code>chdir</code> blocks can be nested, but in a
00816  *  multi-threaded program an error will be raised if a thread attempts
00817  *  to open a <code>chdir</code> block while another thread has one
00818  *  open.
00819  *
00820  *     Dir.chdir("/var/spool/mail")
00821  *     puts Dir.pwd
00822  *     Dir.chdir("/tmp") do
00823  *       puts Dir.pwd
00824  *       Dir.chdir("/usr") do
00825  *         puts Dir.pwd
00826  *       end
00827  *       puts Dir.pwd
00828  *     end
00829  *     puts Dir.pwd
00830  *
00831  *  <em>produces:</em>
00832  *
00833  *     /var/spool/mail
00834  *     /tmp
00835  *     /usr
00836  *     /tmp
00837  *     /var/spool/mail
00838  */
00839 static VALUE
00840 dir_s_chdir(int argc, VALUE *argv, VALUE obj)
00841 {
00842     VALUE path = Qnil;
00843 
00844     rb_secure(2);
00845     if (rb_scan_args(argc, argv, "01", &path) == 1) {
00846         FilePathValue(path);
00847         path = rb_str_encode_ospath(path);
00848     }
00849     else {
00850         const char *dist = getenv("HOME");
00851         if (!dist) {
00852             dist = getenv("LOGDIR");
00853             if (!dist) rb_raise(rb_eArgError, "HOME/LOGDIR not set");
00854         }
00855         path = rb_str_new2(dist);
00856     }
00857 
00858     if (chdir_blocking > 0) {
00859         if (!rb_block_given_p() || rb_thread_current() != chdir_thread)
00860             rb_warn("conflicting chdir during another chdir block");
00861     }
00862 
00863     if (rb_block_given_p()) {
00864         struct chdir_data args;
00865 
00866         args.old_path = rb_str_encode_ospath(rb_dir_getwd());
00867         args.new_path = path;
00868         args.done = FALSE;
00869         return rb_ensure(chdir_yield, (VALUE)&args, chdir_restore, (VALUE)&args);
00870     }
00871     dir_chdir(path);
00872 
00873     return INT2FIX(0);
00874 }
00875 
00876 VALUE
00877 rb_dir_getwd(void)
00878 {
00879     char *path;
00880     VALUE cwd;
00881 
00882     rb_secure(4);
00883     path = my_getcwd();
00884     cwd = rb_tainted_str_new2(path);
00885     rb_enc_associate(cwd, rb_filesystem_encoding());
00886 
00887     xfree(path);
00888     return cwd;
00889 }
00890 
00891 /*
00892  *  call-seq:
00893  *     Dir.getwd -> string
00894  *     Dir.pwd -> string
00895  *
00896  *  Returns the path to the current working directory of this process as
00897  *  a string.
00898  *
00899  *     Dir.chdir("/tmp")   #=> 0
00900  *     Dir.getwd           #=> "/tmp"
00901  */
00902 static VALUE
00903 dir_s_getwd(VALUE dir)
00904 {
00905     return rb_dir_getwd();
00906 }
00907 
00908 static void
00909 check_dirname(volatile VALUE *dir)
00910 {
00911     VALUE d = *dir;
00912     char *path, *pend;
00913 
00914     rb_secure(2);
00915     FilePathValue(d);
00916     path = RSTRING_PTR(d);
00917     if (path && *(pend = rb_path_end(rb_path_skip_prefix(path)))) {
00918         d = rb_str_subseq(d, 0, pend - path);
00919     }
00920     *dir = rb_str_encode_ospath(d);
00921 }
00922 
00923 #if defined(HAVE_CHROOT)
00924 /*
00925  *  call-seq:
00926  *     Dir.chroot( string ) -> 0
00927  *
00928  *  Changes this process's idea of the file system root. Only a
00929  *  privileged process may make this call. Not available on all
00930  *  platforms. On Unix systems, see <code>chroot(2)</code> for more
00931  *  information.
00932  */
00933 static VALUE
00934 dir_s_chroot(VALUE dir, VALUE path)
00935 {
00936     check_dirname(&path);
00937     if (chroot(RSTRING_PTR(path)) == -1)
00938         rb_sys_fail_path(path);
00939 
00940     return INT2FIX(0);
00941 }
00942 #else
00943 #define dir_s_chroot rb_f_notimplement
00944 #endif
00945 
00946 /*
00947  *  call-seq:
00948  *     Dir.mkdir( string [, integer] ) -> 0
00949  *
00950  *  Makes a new directory named by <i>string</i>, with permissions
00951  *  specified by the optional parameter <i>anInteger</i>. The
00952  *  permissions may be modified by the value of
00953  *  <code>File::umask</code>, and are ignored on NT. Raises a
00954  *  <code>SystemCallError</code> if the directory cannot be created. See
00955  *  also the discussion of permissions in the class documentation for
00956  *  <code>File</code>.
00957  *
00958  *    Dir.mkdir(File.join(Dir.home, ".foo"), 0700) #=> 0
00959  *
00960  */
00961 static VALUE
00962 dir_s_mkdir(int argc, VALUE *argv, VALUE obj)
00963 {
00964     VALUE path, vmode;
00965     int mode;
00966 
00967     if (rb_scan_args(argc, argv, "11", &path, &vmode) == 2) {
00968         mode = NUM2INT(vmode);
00969     }
00970     else {
00971         mode = 0777;
00972     }
00973 
00974     check_dirname(&path);
00975     if (mkdir(RSTRING_PTR(path), mode) == -1)
00976         rb_sys_fail_path(path);
00977 
00978     return INT2FIX(0);
00979 }
00980 
00981 /*
00982  *  call-seq:
00983  *     Dir.delete( string ) -> 0
00984  *     Dir.rmdir( string ) -> 0
00985  *     Dir.unlink( string ) -> 0
00986  *
00987  *  Deletes the named directory. Raises a subclass of
00988  *  <code>SystemCallError</code> if the directory isn't empty.
00989  */
00990 static VALUE
00991 dir_s_rmdir(VALUE obj, VALUE dir)
00992 {
00993     check_dirname(&dir);
00994     if (rmdir(RSTRING_PTR(dir)) < 0)
00995         rb_sys_fail_path(dir);
00996 
00997     return INT2FIX(0);
00998 }
00999 
01000 static VALUE
01001 sys_warning_1(VALUE mesg)
01002 {
01003     rb_sys_warning("%s:%s", strerror(errno), (const char *)mesg);
01004     return Qnil;
01005 }
01006 
01007 #define GLOB_VERBOSE    (1U << (sizeof(int) * CHAR_BIT - 1))
01008 #define sys_warning(val) \
01009     (void)((flags & GLOB_VERBOSE) && rb_protect(sys_warning_1, (VALUE)(val), 0))
01010 
01011 #define GLOB_ALLOC(type) ((type *)malloc(sizeof(type)))
01012 #define GLOB_ALLOC_N(type, n) ((type *)malloc(sizeof(type) * (n)))
01013 #define GLOB_FREE(ptr) free(ptr)
01014 #define GLOB_JUMP_TAG(status) (((status) == -1) ? rb_memerror() : rb_jump_tag(status))
01015 
01016 /*
01017  * ENOTDIR can be returned by stat(2) if a non-leaf element of the path
01018  * is not a directory.
01019  */
01020 #define to_be_ignored(e) ((e) == ENOENT || (e) == ENOTDIR)
01021 
01022 /* System call with warning */
01023 static int
01024 do_stat(const char *path, struct stat *pst, int flags)
01025 
01026 {
01027     int ret = stat(path, pst);
01028     if (ret < 0 && !to_be_ignored(errno))
01029         sys_warning(path);
01030 
01031     return ret;
01032 }
01033 
01034 static int
01035 do_lstat(const char *path, struct stat *pst, int flags)
01036 {
01037     int ret = lstat(path, pst);
01038     if (ret < 0 && !to_be_ignored(errno))
01039         sys_warning(path);
01040 
01041     return ret;
01042 }
01043 
01044 static DIR *
01045 do_opendir(const char *path, int flags, rb_encoding *enc)
01046 {
01047     DIR *dirp;
01048 #ifdef _WIN32
01049     volatile VALUE tmp;
01050     if (enc != rb_usascii_encoding() &&
01051         enc != rb_ascii8bit_encoding() &&
01052         enc != rb_utf8_encoding()) {
01053         tmp = rb_enc_str_new(path, strlen(path), enc);
01054         tmp = rb_str_encode_ospath(tmp);
01055         path = RSTRING_PTR(tmp);
01056     }
01057 #endif
01058     dirp = opendir(path);
01059     if (dirp == NULL && !to_be_ignored(errno))
01060         sys_warning(path);
01061 
01062     return dirp;
01063 }
01064 
01065 /* Return nonzero if S has any special globbing chars in it.  */
01066 static int
01067 has_magic(const char *p, const char *pend, int flags, rb_encoding *enc)
01068 {
01069     const int escape = !(flags & FNM_NOESCAPE);
01070     const int nocase = flags & FNM_CASEFOLD;
01071 
01072     register char c;
01073 
01074     while (p < pend && (c = *p++) != 0) {
01075         switch (c) {
01076           case '*':
01077           case '?':
01078           case '[':
01079             return 1;
01080 
01081           case '\\':
01082             if (escape && !(c = *p++))
01083                 return 0;
01084             continue;
01085 
01086           default:
01087             if (!FNM_SYSCASE && ISALPHA(c) && nocase)
01088                 return 1;
01089         }
01090 
01091         p = Next(p-1, pend, enc);
01092     }
01093 
01094     return 0;
01095 }
01096 
01097 /* Find separator in globbing pattern. */
01098 static char *
01099 find_dirsep(const char *p, const char *pend, int flags, rb_encoding *enc)
01100 {
01101     const int escape = !(flags & FNM_NOESCAPE);
01102 
01103     register char c;
01104     int open = 0;
01105 
01106     while ((c = *p++) != 0) {
01107         switch (c) {
01108           case '[':
01109             open = 1;
01110             continue;
01111           case ']':
01112             open = 0;
01113             continue;
01114 
01115           case '/':
01116             if (!open)
01117                 return (char *)p-1;
01118             continue;
01119 
01120           case '\\':
01121             if (escape && !(c = *p++))
01122                 return (char *)p-1;
01123             continue;
01124         }
01125 
01126         p = Next(p-1, pend, enc);
01127     }
01128 
01129     return (char *)p-1;
01130 }
01131 
01132 /* Remove escaping backslashes */
01133 static void
01134 remove_backslashes(char *p, rb_encoding *enc)
01135 {
01136     register const char *pend = p + strlen(p);
01137     char *t = p;
01138     char *s = p;
01139 
01140     while (*p) {
01141         if (*p == '\\') {
01142             if (t != s)
01143                 memmove(t, s, p - s);
01144             t += p - s;
01145             s = ++p;
01146             if (!*p) break;
01147         }
01148         Inc(p, pend, enc);
01149     }
01150 
01151     while (*p++);
01152 
01153     if (t != s)
01154         memmove(t, s, p - s); /* move '\0' too */
01155 }
01156 
01157 /* Globing pattern */
01158 enum glob_pattern_type { PLAIN, MAGICAL, RECURSIVE, MATCH_ALL, MATCH_DIR };
01159 
01160 struct glob_pattern {
01161     char *str;
01162     enum glob_pattern_type type;
01163     struct glob_pattern *next;
01164 };
01165 
01166 static void glob_free_pattern(struct glob_pattern *list);
01167 
01168 static struct glob_pattern *
01169 glob_make_pattern(const char *p, const char *e, int flags, rb_encoding *enc)
01170 {
01171     struct glob_pattern *list, *tmp, **tail = &list;
01172     int dirsep = 0; /* pattern is terminated with '/' */
01173 
01174     while (p < e && *p) {
01175         tmp = GLOB_ALLOC(struct glob_pattern);
01176         if (!tmp) goto error;
01177         if (p[0] == '*' && p[1] == '*' && p[2] == '/') {
01178             /* fold continuous RECURSIVEs (needed in glob_helper) */
01179             do { p += 3; while (*p == '/') p++; } while (p[0] == '*' && p[1] == '*' && p[2] == '/');
01180             tmp->type = RECURSIVE;
01181             tmp->str = 0;
01182             dirsep = 1;
01183         }
01184         else {
01185             const char *m = find_dirsep(p, e, flags, enc);
01186             int magic = has_magic(p, m, flags, enc);
01187             char *buf;
01188 
01189             if (!magic && *m) {
01190                 const char *m2;
01191                 while (!has_magic(m+1, m2 = find_dirsep(m+1, e, flags, enc), flags, enc) &&
01192                        *m2) {
01193                     m = m2;
01194                 }
01195             }
01196             buf = GLOB_ALLOC_N(char, m-p+1);
01197             if (!buf) {
01198                 GLOB_FREE(tmp);
01199                 goto error;
01200             }
01201             memcpy(buf, p, m-p);
01202             buf[m-p] = '\0';
01203             tmp->type = magic ? MAGICAL : PLAIN;
01204             tmp->str = buf;
01205             if (*m) {
01206                 dirsep = 1;
01207                 p = m + 1;
01208             }
01209             else {
01210                 dirsep = 0;
01211                 p = m;
01212             }
01213         }
01214         *tail = tmp;
01215         tail = &tmp->next;
01216     }
01217 
01218     tmp = GLOB_ALLOC(struct glob_pattern);
01219     if (!tmp) {
01220       error:
01221         *tail = 0;
01222         glob_free_pattern(list);
01223         return 0;
01224     }
01225     tmp->type = dirsep ? MATCH_DIR : MATCH_ALL;
01226     tmp->str = 0;
01227     *tail = tmp;
01228     tmp->next = 0;
01229 
01230     return list;
01231 }
01232 
01233 static void
01234 glob_free_pattern(struct glob_pattern *list)
01235 {
01236     while (list) {
01237         struct glob_pattern *tmp = list;
01238         list = list->next;
01239         if (tmp->str)
01240             GLOB_FREE(tmp->str);
01241         GLOB_FREE(tmp);
01242     }
01243 }
01244 
01245 static char *
01246 join_path(const char *path, int dirsep, const char *name)
01247 {
01248     long len = strlen(path);
01249     long len2 = strlen(name)+(dirsep?1:0)+1;
01250     char *buf = GLOB_ALLOC_N(char, len+len2);
01251 
01252     if (!buf) return 0;
01253     memcpy(buf, path, len);
01254     if (dirsep) {
01255         buf[len++] = '/';
01256     }
01257     buf[len] = '\0';
01258     strlcat(buf+len, name, len2);
01259     return buf;
01260 }
01261 
01262 enum answer { YES, NO, UNKNOWN };
01263 
01264 #ifndef S_ISDIR
01265 #   define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
01266 #endif
01267 
01268 #ifndef S_ISLNK
01269 #  ifndef S_IFLNK
01270 #    define S_ISLNK(m) (0)
01271 #  else
01272 #    define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
01273 #  endif
01274 #endif
01275 
01276 struct glob_args {
01277     void (*func)(const char *, VALUE, void *);
01278     const char *path;
01279     VALUE value;
01280     rb_encoding *enc;
01281 };
01282 
01283 static VALUE
01284 glob_func_caller(VALUE val)
01285 {
01286     struct glob_args *args = (struct glob_args *)val;
01287 
01288     (*args->func)(args->path, args->value, args->enc);
01289     return Qnil;
01290 }
01291 
01292 #define glob_call_func(func, path, arg, enc) (*(func))((path), (arg), (enc))
01293 
01294 static int
01295 glob_helper(
01296     const char *path,
01297     int dirsep, /* '/' should be placed before appending child entry's name to 'path'. */
01298     enum answer exist, /* Does 'path' indicate an existing entry? */
01299     enum answer isdir, /* Does 'path' indicate a directory or a symlink to a directory? */
01300     struct glob_pattern **beg,
01301     struct glob_pattern **end,
01302     int flags,
01303     ruby_glob_func *func,
01304     VALUE arg,
01305     rb_encoding *enc)
01306 {
01307     struct stat st;
01308     int status = 0;
01309     struct glob_pattern **cur, **new_beg, **new_end;
01310     int plain = 0, magical = 0, recursive = 0, match_all = 0, match_dir = 0;
01311     int escape = !(flags & FNM_NOESCAPE);
01312 
01313     for (cur = beg; cur < end; ++cur) {
01314         struct glob_pattern *p = *cur;
01315         if (p->type == RECURSIVE) {
01316             recursive = 1;
01317             p = p->next;
01318         }
01319         switch (p->type) {
01320           case PLAIN:
01321             plain = 1;
01322             break;
01323           case MAGICAL:
01324             magical = 1;
01325             break;
01326           case MATCH_ALL:
01327             match_all = 1;
01328             break;
01329           case MATCH_DIR:
01330             match_dir = 1;
01331             break;
01332           case RECURSIVE:
01333             rb_bug("continuous RECURSIVEs");
01334         }
01335     }
01336 
01337     if (*path) {
01338         if (match_all && exist == UNKNOWN) {
01339             if (do_lstat(path, &st, flags) == 0) {
01340                 exist = YES;
01341                 isdir = S_ISDIR(st.st_mode) ? YES : S_ISLNK(st.st_mode) ? UNKNOWN : NO;
01342             }
01343             else {
01344                 exist = NO;
01345                 isdir = NO;
01346             }
01347         }
01348         if (match_dir && isdir == UNKNOWN) {
01349             if (do_stat(path, &st, flags) == 0) {
01350                 exist = YES;
01351                 isdir = S_ISDIR(st.st_mode) ? YES : NO;
01352             }
01353             else {
01354                 exist = NO;
01355                 isdir = NO;
01356             }
01357         }
01358         if (match_all && exist == YES) {
01359             status = glob_call_func(func, path, arg, enc);
01360             if (status) return status;
01361         }
01362         if (match_dir && isdir == YES) {
01363             char *tmp = join_path(path, dirsep, "");
01364             if (!tmp) return -1;
01365             status = glob_call_func(func, tmp, arg, enc);
01366             GLOB_FREE(tmp);
01367             if (status) return status;
01368         }
01369     }
01370 
01371     if (exist == NO || isdir == NO) return 0;
01372 
01373     if (magical || recursive) {
01374         struct dirent *dp;
01375         DIR *dirp;
01376         IF_HAVE_READDIR_R(DEFINE_STRUCT_DIRENT entry);
01377         dirp = do_opendir(*path ? path : ".", flags, enc);
01378         if (dirp == NULL) return 0;
01379 
01380         while (READDIR(dirp, enc, &STRUCT_DIRENT(entry), dp)) {
01381             char *buf = join_path(path, dirsep, dp->d_name);
01382             enum answer new_isdir = UNKNOWN;
01383 
01384             if (!buf) {
01385                 status = -1;
01386                 break;
01387             }
01388             if (recursive && strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0
01389                 && fnmatch("*", rb_usascii_encoding(), dp->d_name, flags) == 0) {
01390 #ifndef _WIN32
01391                 if (do_lstat(buf, &st, flags) == 0)
01392                     new_isdir = S_ISDIR(st.st_mode) ? YES : S_ISLNK(st.st_mode) ? UNKNOWN : NO;
01393                 else
01394                     new_isdir = NO;
01395 #else
01396                 new_isdir = dp->d_isdir ? (!dp->d_isrep ? YES : UNKNOWN) : NO;
01397 #endif
01398             }
01399 
01400             new_beg = new_end = GLOB_ALLOC_N(struct glob_pattern *, (end - beg) * 2);
01401             if (!new_beg) {
01402                 GLOB_FREE(buf);
01403                 status = -1;
01404                 break;
01405             }
01406 
01407             for (cur = beg; cur < end; ++cur) {
01408                 struct glob_pattern *p = *cur;
01409                 if (p->type == RECURSIVE) {
01410                     if (new_isdir == YES) /* not symlink but real directory */
01411                         *new_end++ = p; /* append recursive pattern */
01412                     p = p->next; /* 0 times recursion */
01413                 }
01414                 if (p->type == PLAIN || p->type == MAGICAL) {
01415                     if (fnmatch(p->str, enc, dp->d_name, flags) == 0)
01416                         *new_end++ = p->next;
01417                 }
01418             }
01419 
01420             status = glob_helper(buf, 1, YES, new_isdir, new_beg, new_end,
01421                                  flags, func, arg, enc);
01422             GLOB_FREE(buf);
01423             GLOB_FREE(new_beg);
01424             if (status) break;
01425         }
01426 
01427         closedir(dirp);
01428     }
01429     else if (plain) {
01430         struct glob_pattern **copy_beg, **copy_end, **cur2;
01431 
01432         copy_beg = copy_end = GLOB_ALLOC_N(struct glob_pattern *, end - beg);
01433         if (!copy_beg) return -1;
01434         for (cur = beg; cur < end; ++cur)
01435             *copy_end++ = (*cur)->type == PLAIN ? *cur : 0;
01436 
01437         for (cur = copy_beg; cur < copy_end; ++cur) {
01438             if (*cur) {
01439                 char *buf;
01440                 char *name;
01441                 size_t len = strlen((*cur)->str) + 1;
01442                 name = GLOB_ALLOC_N(char, len);
01443                 if (!name) {
01444                     status = -1;
01445                     break;
01446                 }
01447                 memcpy(name, (*cur)->str, len);
01448                 if (escape) remove_backslashes(name, enc);
01449 
01450                 new_beg = new_end = GLOB_ALLOC_N(struct glob_pattern *, end - beg);
01451                 if (!new_beg) {
01452                     GLOB_FREE(name);
01453                     status = -1;
01454                     break;
01455                 }
01456                 *new_end++ = (*cur)->next;
01457                 for (cur2 = cur + 1; cur2 < copy_end; ++cur2) {
01458                     if (*cur2 && fnmatch((*cur2)->str, enc, name, flags) == 0) {
01459                         *new_end++ = (*cur2)->next;
01460                         *cur2 = 0;
01461                     }
01462                 }
01463 
01464                 buf = join_path(path, dirsep, name);
01465                 GLOB_FREE(name);
01466                 if (!buf) {
01467                     GLOB_FREE(new_beg);
01468                     status = -1;
01469                     break;
01470                 }
01471                 status = glob_helper(buf, 1, UNKNOWN, UNKNOWN, new_beg,
01472                                      new_end, flags, func, arg, enc);
01473                 GLOB_FREE(buf);
01474                 GLOB_FREE(new_beg);
01475                 if (status) break;
01476             }
01477         }
01478 
01479         GLOB_FREE(copy_beg);
01480     }
01481 
01482     return status;
01483 }
01484 
01485 static int
01486 ruby_glob0(const char *path, int flags, ruby_glob_func *func, VALUE arg, rb_encoding *enc)
01487 {
01488     struct glob_pattern *list;
01489     const char *root, *start;
01490     char *buf;
01491     size_t n;
01492     int status;
01493 
01494     start = root = path;
01495     flags |= FNM_SYSCASE;
01496 #if defined DOSISH
01497     root = rb_path_skip_prefix(root);
01498 #endif
01499 
01500     if (root && *root == '/') root++;
01501 
01502     n = root - start;
01503     buf = GLOB_ALLOC_N(char, n + 1);
01504     if (!buf) return -1;
01505     MEMCPY(buf, start, char, n);
01506     buf[n] = '\0';
01507 
01508     list = glob_make_pattern(root, root + strlen(root), flags, enc);
01509     if (!list) {
01510         GLOB_FREE(buf);
01511         return -1;
01512     }
01513     status = glob_helper(buf, 0, UNKNOWN, UNKNOWN, &list, &list + 1, flags, func, arg, enc);
01514     glob_free_pattern(list);
01515     GLOB_FREE(buf);
01516 
01517     return status;
01518 }
01519 
01520 int
01521 ruby_glob(const char *path, int flags, ruby_glob_func *func, VALUE arg)
01522 {
01523     return ruby_glob0(path, flags & ~GLOB_VERBOSE, func, arg,
01524                       rb_ascii8bit_encoding());
01525 }
01526 
01527 static int
01528 rb_glob_caller(const char *path, VALUE a, void *enc)
01529 {
01530     int status;
01531     struct glob_args *args = (struct glob_args *)a;
01532 
01533     args->path = path;
01534     rb_protect(glob_func_caller, a, &status);
01535     return status;
01536 }
01537 
01538 static int
01539 rb_glob2(const char *path, int flags,
01540          void (*func)(const char *, VALUE, void *), VALUE arg,
01541          rb_encoding* enc)
01542 {
01543     struct glob_args args;
01544 
01545     args.func = func;
01546     args.value = arg;
01547     args.enc = enc;
01548 
01549     if (flags & FNM_SYSCASE) {
01550         rb_warning("Dir.glob() ignores File::FNM_CASEFOLD");
01551     }
01552 
01553     return ruby_glob0(path, flags | GLOB_VERBOSE, rb_glob_caller, (VALUE)&args,
01554                       enc);
01555 }
01556 
01557 void
01558 rb_glob(const char *path, void (*func)(const char *, VALUE, void *), VALUE arg)
01559 {
01560     int status = rb_glob2(path, 0, func, arg, rb_ascii8bit_encoding());
01561     if (status) GLOB_JUMP_TAG(status);
01562 }
01563 
01564 static void
01565 push_pattern(const char *path, VALUE ary, void *enc)
01566 {
01567     rb_ary_push(ary, rb_external_str_new_with_enc(path, strlen(path), enc));
01568 }
01569 
01570 static int
01571 ruby_brace_expand(const char *str, int flags, ruby_glob_func *func, VALUE arg,
01572                   rb_encoding *enc)
01573 {
01574     const int escape = !(flags & FNM_NOESCAPE);
01575     const char *p = str;
01576     const char *pend = p + strlen(p);
01577     const char *s = p;
01578     const char *lbrace = 0, *rbrace = 0;
01579     int nest = 0, status = 0;
01580 
01581     while (*p) {
01582         if (*p == '{' && nest++ == 0) {
01583             lbrace = p;
01584         }
01585         if (*p == '}' && --nest <= 0) {
01586             rbrace = p;
01587             break;
01588         }
01589         if (*p == '\\' && escape) {
01590             if (!*++p) break;
01591         }
01592         Inc(p, pend, enc);
01593     }
01594 
01595     if (lbrace && rbrace) {
01596         size_t len = strlen(s) + 1;
01597         char *buf = GLOB_ALLOC_N(char, len);
01598         long shift;
01599 
01600         if (!buf) return -1;
01601         memcpy(buf, s, lbrace-s);
01602         shift = (lbrace-s);
01603         p = lbrace;
01604         while (p < rbrace) {
01605             const char *t = ++p;
01606             nest = 0;
01607             while (p < rbrace && !(*p == ',' && nest == 0)) {
01608                 if (*p == '{') nest++;
01609                 if (*p == '}') nest--;
01610                 if (*p == '\\' && escape) {
01611                     if (++p == rbrace) break;
01612                 }
01613                 Inc(p, pend, enc);
01614             }
01615             memcpy(buf+shift, t, p-t);
01616             strlcpy(buf+shift+(p-t), rbrace+1, len-(shift+(p-t)));
01617             status = ruby_brace_expand(buf, flags, func, arg, enc);
01618             if (status) break;
01619         }
01620         GLOB_FREE(buf);
01621     }
01622     else if (!lbrace && !rbrace) {
01623         status = (*func)(s, arg, enc);
01624     }
01625 
01626     return status;
01627 }
01628 
01629 struct brace_args {
01630     ruby_glob_func *func;
01631     VALUE value;
01632     int flags;
01633 };
01634 
01635 static int
01636 glob_brace(const char *path, VALUE val, void *enc)
01637 {
01638     struct brace_args *arg = (struct brace_args *)val;
01639 
01640     return ruby_glob0(path, arg->flags, arg->func, arg->value, enc);
01641 }
01642 
01643 static int
01644 ruby_brace_glob0(const char *str, int flags, ruby_glob_func *func, VALUE arg,
01645                  rb_encoding* enc)
01646 {
01647     struct brace_args args;
01648 
01649     args.func = func;
01650     args.value = arg;
01651     args.flags = flags;
01652     return ruby_brace_expand(str, flags, glob_brace, (VALUE)&args, enc);
01653 }
01654 
01655 int
01656 ruby_brace_glob(const char *str, int flags, ruby_glob_func *func, VALUE arg)
01657 {
01658     return ruby_brace_glob0(str, flags & ~GLOB_VERBOSE, func, arg,
01659                             rb_ascii8bit_encoding());
01660 }
01661 
01662 int
01663 ruby_brace_glob_with_enc(const char *str, int flags, ruby_glob_func *func, VALUE arg, rb_encoding *enc)
01664 {
01665     return ruby_brace_glob0(str, flags & ~GLOB_VERBOSE, func, arg, enc);
01666 }
01667 
01668 static int
01669 push_glob(VALUE ary, VALUE str, int flags)
01670 {
01671     struct glob_args args;
01672     rb_encoding *enc = rb_enc_get(str);
01673 
01674     if (enc == rb_usascii_encoding()) enc = rb_filesystem_encoding();
01675     args.func = push_pattern;
01676     args.value = ary;
01677     args.enc = enc;
01678 
01679     RB_GC_GUARD(str);
01680     return ruby_brace_glob0(RSTRING_PTR(str), flags | GLOB_VERBOSE,
01681                             rb_glob_caller, (VALUE)&args, enc);
01682 }
01683 
01684 static VALUE
01685 rb_push_glob(VALUE str, int flags) /* '\0' is delimiter */
01686 {
01687     long offset = 0;
01688     VALUE ary;
01689 
01690     GlobPathValue(str, TRUE);
01691     ary = rb_ary_new();
01692 
01693     while (offset < RSTRING_LEN(str)) {
01694         char *p, *pend;
01695         int status;
01696         p = RSTRING_PTR(str) + offset;
01697         status = push_glob(ary, rb_enc_str_new(p, strlen(p), rb_enc_get(str)),
01698                            flags);
01699         if (status) GLOB_JUMP_TAG(status);
01700         if (offset >= RSTRING_LEN(str)) break;
01701         p += strlen(p) + 1;
01702         pend = RSTRING_PTR(str) + RSTRING_LEN(str);
01703         while (p < pend && !*p)
01704             p++;
01705         offset = p - RSTRING_PTR(str);
01706     }
01707 
01708     return ary;
01709 }
01710 
01711 static VALUE
01712 dir_globs(long argc, VALUE *argv, int flags)
01713 {
01714     VALUE ary = rb_ary_new();
01715     long i;
01716 
01717     for (i = 0; i < argc; ++i) {
01718         int status;
01719         VALUE str = argv[i];
01720         GlobPathValue(str, TRUE);
01721         status = push_glob(ary, str, flags);
01722         if (status) GLOB_JUMP_TAG(status);
01723     }
01724 
01725     return ary;
01726 }
01727 
01728 /*
01729  *  call-seq:
01730  *     Dir[ array ]                 -> array
01731  *     Dir[ string [, string ...] ] -> array
01732  *
01733  *  Equivalent to calling
01734  *  <code>Dir.glob(</code><i>array,</i><code>0)</code> and
01735  *  <code>Dir.glob([</code><i>string,...</i><code>],0)</code>.
01736  *
01737  */
01738 static VALUE
01739 dir_s_aref(int argc, VALUE *argv, VALUE obj)
01740 {
01741     if (argc == 1) {
01742         return rb_push_glob(argv[0], 0);
01743     }
01744     return dir_globs(argc, argv, 0);
01745 }
01746 
01747 /*
01748  *  call-seq:
01749  *     Dir.glob( pattern, [flags] ) -> array
01750  *     Dir.glob( pattern, [flags] ) {| filename | block }  -> nil
01751  *
01752  *  Returns the filenames found by expanding <i>pattern</i> which is
01753  *  an +Array+ of the patterns or the pattern +String+, either as an
01754  *  <i>array</i> or as parameters to the block. Note that this pattern
01755  *  is not a regexp (it's closer to a shell glob). See
01756  *  <code>File::fnmatch</code> for the meaning of the <i>flags</i>
01757  *  parameter. Note that case sensitivity depends on your system (so
01758  *  <code>File::FNM_CASEFOLD</code> is ignored), as does the order
01759  *  in which the results are returned.
01760  *
01761  *  <code>*</code>::        Matches any file. Can be restricted by
01762  *                          other values in the glob. <code>*</code>
01763  *                          will match all files; <code>c*</code> will
01764  *                          match all files beginning with
01765  *                          <code>c</code>; <code>*c</code> will match
01766  *                          all files ending with <code>c</code>; and
01767  *                          <code>\*c\*</code> will match all files that
01768  *                          have <code>c</code> in them (including at
01769  *                          the beginning or end). Equivalent to
01770  *                          <code>/ .* /x</code> in regexp. Note, this
01771  *                          will not match Unix-like hidden files (dotfiles).
01772  *                          In order to include those in the match results,
01773  *                          you must use something like "{*,.*}".
01774  *  <code>**</code>::       Matches directories recursively.
01775  *  <code>?</code>::        Matches any one character. Equivalent to
01776  *                          <code>/.{1}/</code> in regexp.
01777  *  <code>[set]</code>::    Matches any one character in +set+.
01778  *                          Behaves exactly like character sets in
01779  *                          Regexp, including set negation
01780  *                          (<code>[^a-z]</code>).
01781  *  <code>{p,q}</code>::    Matches either literal <code>p</code> or
01782  *                          literal <code>q</code>. Matching literals
01783  *                          may be more than one character in length.
01784  *                          More than two literals may be specified.
01785  *                          Equivalent to pattern alternation in
01786  *                          regexp.
01787  *  <code></code>::        Escapes the next metacharacter.
01788  *                          Note that this means you cannot use backslash in windows
01789  *                          as part of a glob, i.e. Dir["c:\\foo*"] will not work
01790  *                          use Dir["c:/foo*"] instead
01791  *
01792  *     Dir["config.?"]                     #=> ["config.h"]
01793  *     Dir.glob("config.?")                #=> ["config.h"]
01794  *     Dir.glob("*.[a-z][a-z]")            #=> ["main.rb"]
01795  *     Dir.glob("*.[^r]*")                 #=> ["config.h"]
01796  *     Dir.glob("*.{rb,h}")                #=> ["main.rb", "config.h"]
01797  *     Dir.glob("*")                       #=> ["config.h", "main.rb"]
01798  *     Dir.glob("*", File::FNM_DOTMATCH)   #=> [".", "..", "config.h", "main.rb"]
01799  *
01800  *     rbfiles = File.join("**", "*.rb")
01801  *     Dir.glob(rbfiles)                   #=> ["main.rb",
01802  *                                         #    "lib/song.rb",
01803  *                                         #    "lib/song/karaoke.rb"]
01804  *     libdirs = File.join("**", "lib")
01805  *     Dir.glob(libdirs)                   #=> ["lib"]
01806  *
01807  *     librbfiles = File.join("**", "lib", "**", "*.rb")
01808  *     Dir.glob(librbfiles)                #=> ["lib/song.rb",
01809  *                                         #    "lib/song/karaoke.rb"]
01810  *
01811  *     librbfiles = File.join("**", "lib", "*.rb")
01812  *     Dir.glob(librbfiles)                #=> ["lib/song.rb"]
01813  */
01814 static VALUE
01815 dir_s_glob(int argc, VALUE *argv, VALUE obj)
01816 {
01817     VALUE str, rflags, ary;
01818     int flags;
01819 
01820     if (rb_scan_args(argc, argv, "11", &str, &rflags) == 2)
01821         flags = NUM2INT(rflags);
01822     else
01823         flags = 0;
01824 
01825     ary = rb_check_array_type(str);
01826     if (NIL_P(ary)) {
01827         ary = rb_push_glob(str, flags);
01828     }
01829     else {
01830         volatile VALUE v = ary;
01831         ary = dir_globs(RARRAY_LEN(v), RARRAY_PTR(v), flags);
01832     }
01833 
01834     if (rb_block_given_p()) {
01835         rb_ary_each(ary);
01836         return Qnil;
01837     }
01838     return ary;
01839 }
01840 
01841 static VALUE
01842 dir_open_dir(int argc, VALUE *argv)
01843 {
01844     VALUE dir = rb_funcall2(rb_cDir, rb_intern("open"), argc, argv);
01845     struct dir_data *dirp;
01846 
01847     TypedData_Get_Struct(dir, struct dir_data, &dir_data_type, dirp);
01848     return dir;
01849 }
01850 
01851 
01852 /*
01853  *  call-seq:
01854  *     Dir.foreach( dirname ) {| filename | block }  -> nil
01855  *     Dir.foreach( dirname )                        -> an_enumerator
01856  *
01857  *  Calls the block once for each entry in the named directory, passing
01858  *  the filename of each entry as a parameter to the block.
01859  *
01860  *  If no block is given, an enumerator is returned instead.
01861  *
01862  *     Dir.foreach("testdir") {|x| puts "Got #{x}" }
01863  *
01864  *  <em>produces:</em>
01865  *
01866  *     Got .
01867  *     Got ..
01868  *     Got config.h
01869  *     Got main.rb
01870  *
01871  */
01872 static VALUE
01873 dir_foreach(int argc, VALUE *argv, VALUE io)
01874 {
01875     VALUE dir;
01876 
01877     RETURN_ENUMERATOR(io, argc, argv);
01878     dir = dir_open_dir(argc, argv);
01879     rb_ensure(dir_each, dir, dir_close, dir);
01880     return Qnil;
01881 }
01882 
01883 /*
01884  *  call-seq:
01885  *     Dir.entries( dirname ) -> array
01886  *
01887  *  Returns an array containing all of the filenames in the given
01888  *  directory. Will raise a <code>SystemCallError</code> if the named
01889  *  directory doesn't exist.
01890  *
01891  *     Dir.entries("testdir")   #=> [".", "..", "config.h", "main.rb"]
01892  *
01893  */
01894 static VALUE
01895 dir_entries(int argc, VALUE *argv, VALUE io)
01896 {
01897     VALUE dir;
01898 
01899     dir = dir_open_dir(argc, argv);
01900     return rb_ensure(rb_Array, dir, dir_close, dir);
01901 }
01902 
01903 /*
01904  *  call-seq:
01905  *     File.fnmatch( pattern, path, [flags] ) -> (true or false)
01906  *     File.fnmatch?( pattern, path, [flags] ) -> (true or false)
01907  *
01908  *  Returns true if <i>path</i> matches against <i>pattern</i> The
01909  *  pattern is not a regular expression; instead it follows rules
01910  *  similar to shell filename globbing. It may contain the following
01911  *  metacharacters:
01912  *
01913  *  <code>*</code>::        Matches any file. Can be restricted by
01914  *                          other values in the glob. <code>*</code>
01915  *                          will match all files; <code>c*</code> will
01916  *                          match all files beginning with
01917  *                          <code>c</code>; <code>*c</code> will match
01918  *                          all files ending with <code>c</code>; and
01919  *                          <code>\*c*</code> will match all files that
01920  *                          have <code>c</code> in them (including at
01921  *                          the beginning or end). Equivalent to
01922  *                          <code>/ .* /x</code> in regexp.
01923  *  <code>**</code>::       Matches directories recursively or files
01924  *                          expansively.
01925  *  <code>?</code>::        Matches any one character. Equivalent to
01926  *                          <code>/.{1}/</code> in regexp.
01927  *  <code>[set]</code>::    Matches any one character in +set+.
01928  *                          Behaves exactly like character sets in
01929  *                          Regexp, including set negation
01930  *                          (<code>[^a-z]</code>).
01931  *  <code></code>::        Escapes the next metacharacter.
01932  *
01933  *  <i>flags</i> is a bitwise OR of the <code>FNM_xxx</code>
01934  *  parameters. The same glob pattern and flags are used by
01935  *  <code>Dir::glob</code>.
01936  *
01937  *     File.fnmatch('cat',       'cat')        #=> true  # match entire string
01938  *     File.fnmatch('cat',       'category')   #=> false # only match partial string
01939  *     File.fnmatch('c{at,ub}s', 'cats')       #=> false # { } isn't supported
01940  *
01941  *     File.fnmatch('c?t',     'cat')          #=> true  # '?' match only 1 character
01942  *     File.fnmatch('c??t',    'cat')          #=> false # ditto
01943  *     File.fnmatch('c*',      'cats')         #=> true  # '*' match 0 or more characters
01944  *     File.fnmatch('c*t',     'c/a/b/t')      #=> true  # ditto
01945  *     File.fnmatch('ca[a-z]', 'cat')          #=> true  # inclusive bracket expression
01946  *     File.fnmatch('ca[^t]',  'cat')          #=> false # exclusive bracket expression ('^' or '!')
01947  *
01948  *     File.fnmatch('cat', 'CAT')                     #=> false # case sensitive
01949  *     File.fnmatch('cat', 'CAT', File::FNM_CASEFOLD) #=> true  # case insensitive
01950  *
01951  *     File.fnmatch('?',   '/', File::FNM_PATHNAME)  #=> false # wildcard doesn't match '/' on FNM_PATHNAME
01952  *     File.fnmatch('*',   '/', File::FNM_PATHNAME)  #=> false # ditto
01953  *     File.fnmatch('[/]', '/', File::FNM_PATHNAME)  #=> false # ditto
01954  *
01955  *     File.fnmatch('\?',   '?')                       #=> true  # escaped wildcard becomes ordinary
01956  *     File.fnmatch('\a',   'a')                       #=> true  # escaped ordinary remains ordinary
01957  *     File.fnmatch('\a',   '\a', File::FNM_NOESCAPE)  #=> true  # FNM_NOESACPE makes '\' ordinary
01958  *     File.fnmatch('[\?]', '?')                       #=> true  # can escape inside bracket expression
01959  *
01960  *     File.fnmatch('*',   '.profile')                      #=> false # wildcard doesn't match leading
01961  *     File.fnmatch('*',   '.profile', File::FNM_DOTMATCH)  #=> true  # period by default.
01962  *     File.fnmatch('.*',  '.profile')                      #=> true
01963  *
01964  *     rbfiles = '**' '/' '*.rb' # you don't have to do like this. just write in single string.
01965  *     File.fnmatch(rbfiles, 'main.rb')                    #=> false
01966  *     File.fnmatch(rbfiles, './main.rb')                  #=> false
01967  *     File.fnmatch(rbfiles, 'lib/song.rb')                #=> true
01968  *     File.fnmatch('**.rb', 'main.rb')                    #=> true
01969  *     File.fnmatch('**.rb', './main.rb')                  #=> false
01970  *     File.fnmatch('**.rb', 'lib/song.rb')                #=> true
01971  *     File.fnmatch('*',           'dave/.profile')                      #=> true
01972  *
01973  *     pattern = '*' '/' '*'
01974  *     File.fnmatch(pattern, 'dave/.profile', File::FNM_PATHNAME)  #=> false
01975  *     File.fnmatch(pattern, 'dave/.profile', File::FNM_PATHNAME | File::FNM_DOTMATCH) #=> true
01976  *
01977  *     pattern = '**' '/' 'foo'
01978  *     File.fnmatch(pattern, 'a/b/c/foo', File::FNM_PATHNAME)     #=> true
01979  *     File.fnmatch(pattern, '/a/b/c/foo', File::FNM_PATHNAME)    #=> true
01980  *     File.fnmatch(pattern, 'c:/a/b/c/foo', File::FNM_PATHNAME)  #=> true
01981  *     File.fnmatch(pattern, 'a/.b/c/foo', File::FNM_PATHNAME)    #=> false
01982  *     File.fnmatch(pattern, 'a/.b/c/foo', File::FNM_PATHNAME | File::FNM_DOTMATCH) #=> true
01983  */
01984 static VALUE
01985 file_s_fnmatch(int argc, VALUE *argv, VALUE obj)
01986 {
01987     VALUE pattern, path;
01988     VALUE rflags;
01989     int flags;
01990 
01991     if (rb_scan_args(argc, argv, "21", &pattern, &path, &rflags) == 3)
01992         flags = NUM2INT(rflags);
01993     else
01994         flags = 0;
01995 
01996     StringValue(pattern);
01997     FilePathStringValue(path);
01998 
01999     if (fnmatch(RSTRING_PTR(pattern), rb_enc_get(pattern), RSTRING_PTR(path),
02000                 flags) == 0)
02001         return Qtrue;
02002 
02003     return Qfalse;
02004 }
02005 
02006 /*
02007  *  call-seq:
02008  *    Dir.home()       -> "/home/me"
02009  *    Dir.home("root") -> "/root"
02010  *
02011  *  Returns the home directory of the current user or the named user
02012  *  if given.
02013  */
02014 static VALUE
02015 dir_s_home(int argc, VALUE *argv, VALUE obj)
02016 {
02017     VALUE user;
02018     const char *u = 0;
02019 
02020     rb_scan_args(argc, argv, "01", &user);
02021     if (!NIL_P(user)) {
02022         SafeStringValue(user);
02023         u = StringValueCStr(user);
02024     }
02025     return rb_home_dir(u, rb_str_new(0, 0));
02026 }
02027 
02028 /*
02029  *  Objects of class <code>Dir</code> are directory streams representing
02030  *  directories in the underlying file system. They provide a variety of
02031  *  ways to list directories and their contents. See also
02032  *  <code>File</code>.
02033  *
02034  *  The directory used in these examples contains the two regular files
02035  *  (<code>config.h</code> and <code>main.rb</code>), the parent
02036  *  directory (<code>..</code>), and the directory itself
02037  *  (<code>.</code>).
02038  */
02039 void
02040 Init_Dir(void)
02041 {
02042     rb_cDir = rb_define_class("Dir", rb_cObject);
02043 
02044     rb_include_module(rb_cDir, rb_mEnumerable);
02045 
02046     rb_define_alloc_func(rb_cDir, dir_s_alloc);
02047     rb_define_singleton_method(rb_cDir, "open", dir_s_open, -1);
02048     rb_define_singleton_method(rb_cDir, "foreach", dir_foreach, -1);
02049     rb_define_singleton_method(rb_cDir, "entries", dir_entries, -1);
02050 
02051     rb_define_method(rb_cDir,"initialize", dir_initialize, -1);
02052     rb_define_method(rb_cDir,"path", dir_path, 0);
02053     rb_define_method(rb_cDir,"to_path", dir_path, 0);
02054     rb_define_method(rb_cDir,"inspect", dir_inspect, 0);
02055     rb_define_method(rb_cDir,"read", dir_read, 0);
02056     rb_define_method(rb_cDir,"each", dir_each, 0);
02057     rb_define_method(rb_cDir,"rewind", dir_rewind, 0);
02058     rb_define_method(rb_cDir,"tell", dir_tell, 0);
02059     rb_define_method(rb_cDir,"seek", dir_seek, 1);
02060     rb_define_method(rb_cDir,"pos", dir_tell, 0);
02061     rb_define_method(rb_cDir,"pos=", dir_set_pos, 1);
02062     rb_define_method(rb_cDir,"close", dir_close, 0);
02063 
02064     rb_define_singleton_method(rb_cDir,"chdir", dir_s_chdir, -1);
02065     rb_define_singleton_method(rb_cDir,"getwd", dir_s_getwd, 0);
02066     rb_define_singleton_method(rb_cDir,"pwd", dir_s_getwd, 0);
02067     rb_define_singleton_method(rb_cDir,"chroot", dir_s_chroot, 1);
02068     rb_define_singleton_method(rb_cDir,"mkdir", dir_s_mkdir, -1);
02069     rb_define_singleton_method(rb_cDir,"rmdir", dir_s_rmdir, 1);
02070     rb_define_singleton_method(rb_cDir,"delete", dir_s_rmdir, 1);
02071     rb_define_singleton_method(rb_cDir,"unlink", dir_s_rmdir, 1);
02072     rb_define_singleton_method(rb_cDir,"home", dir_s_home, -1);
02073 
02074     rb_define_singleton_method(rb_cDir,"glob", dir_s_glob, -1);
02075     rb_define_singleton_method(rb_cDir,"[]", dir_s_aref, -1);
02076     rb_define_singleton_method(rb_cDir,"exist?", rb_file_directory_p, 1); /* in file.c */
02077     rb_define_singleton_method(rb_cDir,"exists?", rb_file_directory_p, 1); /* in file.c */
02078 
02079     rb_define_singleton_method(rb_cFile,"fnmatch", file_s_fnmatch, -1);
02080     rb_define_singleton_method(rb_cFile,"fnmatch?", file_s_fnmatch, -1);
02081 
02082     rb_file_const("FNM_NOESCAPE", INT2FIX(FNM_NOESCAPE));
02083     rb_file_const("FNM_PATHNAME", INT2FIX(FNM_PATHNAME));
02084     rb_file_const("FNM_DOTMATCH", INT2FIX(FNM_DOTMATCH));
02085     rb_file_const("FNM_CASEFOLD", INT2FIX(FNM_CASEFOLD));
02086     rb_file_const("FNM_SYSCASE", INT2FIX(FNM_SYSCASE));
02087 }
02088