Ruby 1.9.3p327(2012-11-10revision37606)
dir.c
Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   dir.c -
00004 
00005   $Author: usa $
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     long len;
00914     rb_encoding *enc;
00915 
00916     rb_secure(2);
00917     FilePathValue(d);
00918     enc = rb_enc_get(d);
00919     RSTRING_GETMEM(d, path, len);
00920     pend = path + len;
00921     pend = rb_enc_path_end(rb_enc_path_skip_prefix(path, pend, enc), pend, enc);
00922     if (pend - path < len) {
00923         d = rb_str_subseq(d, 0, pend - path);
00924     }
00925     *dir = rb_str_encode_ospath(d);
00926 }
00927 
00928 #if defined(HAVE_CHROOT)
00929 /*
00930  *  call-seq:
00931  *     Dir.chroot( string ) -> 0
00932  *
00933  *  Changes this process's idea of the file system root. Only a
00934  *  privileged process may make this call. Not available on all
00935  *  platforms. On Unix systems, see <code>chroot(2)</code> for more
00936  *  information.
00937  */
00938 static VALUE
00939 dir_s_chroot(VALUE dir, VALUE path)
00940 {
00941     check_dirname(&path);
00942     if (chroot(RSTRING_PTR(path)) == -1)
00943         rb_sys_fail_path(path);
00944 
00945     return INT2FIX(0);
00946 }
00947 #else
00948 #define dir_s_chroot rb_f_notimplement
00949 #endif
00950 
00951 /*
00952  *  call-seq:
00953  *     Dir.mkdir( string [, integer] ) -> 0
00954  *
00955  *  Makes a new directory named by <i>string</i>, with permissions
00956  *  specified by the optional parameter <i>anInteger</i>. The
00957  *  permissions may be modified by the value of
00958  *  <code>File::umask</code>, and are ignored on NT. Raises a
00959  *  <code>SystemCallError</code> if the directory cannot be created. See
00960  *  also the discussion of permissions in the class documentation for
00961  *  <code>File</code>.
00962  *
00963  *    Dir.mkdir(File.join(Dir.home, ".foo"), 0700) #=> 0
00964  *
00965  */
00966 static VALUE
00967 dir_s_mkdir(int argc, VALUE *argv, VALUE obj)
00968 {
00969     VALUE path, vmode;
00970     int mode;
00971 
00972     if (rb_scan_args(argc, argv, "11", &path, &vmode) == 2) {
00973         mode = NUM2INT(vmode);
00974     }
00975     else {
00976         mode = 0777;
00977     }
00978 
00979     check_dirname(&path);
00980     if (mkdir(RSTRING_PTR(path), mode) == -1)
00981         rb_sys_fail_path(path);
00982 
00983     return INT2FIX(0);
00984 }
00985 
00986 /*
00987  *  call-seq:
00988  *     Dir.delete( string ) -> 0
00989  *     Dir.rmdir( string ) -> 0
00990  *     Dir.unlink( string ) -> 0
00991  *
00992  *  Deletes the named directory. Raises a subclass of
00993  *  <code>SystemCallError</code> if the directory isn't empty.
00994  */
00995 static VALUE
00996 dir_s_rmdir(VALUE obj, VALUE dir)
00997 {
00998     check_dirname(&dir);
00999     if (rmdir(RSTRING_PTR(dir)) < 0)
01000         rb_sys_fail_path(dir);
01001 
01002     return INT2FIX(0);
01003 }
01004 
01005 static VALUE
01006 sys_warning_1(VALUE mesg)
01007 {
01008     rb_sys_warning("%s:%s", strerror(errno), (const char *)mesg);
01009     return Qnil;
01010 }
01011 
01012 #define GLOB_VERBOSE    (1U << (sizeof(int) * CHAR_BIT - 1))
01013 #define sys_warning(val) \
01014     (void)((flags & GLOB_VERBOSE) && rb_protect(sys_warning_1, (VALUE)(val), 0))
01015 
01016 #define GLOB_ALLOC(type) ((type *)malloc(sizeof(type)))
01017 #define GLOB_ALLOC_N(type, n) ((type *)malloc(sizeof(type) * (n)))
01018 #define GLOB_FREE(ptr) free(ptr)
01019 #define GLOB_JUMP_TAG(status) (((status) == -1) ? rb_memerror() : rb_jump_tag(status))
01020 
01021 /*
01022  * ENOTDIR can be returned by stat(2) if a non-leaf element of the path
01023  * is not a directory.
01024  */
01025 #define to_be_ignored(e) ((e) == ENOENT || (e) == ENOTDIR)
01026 
01027 /* System call with warning */
01028 static int
01029 do_stat(const char *path, struct stat *pst, int flags)
01030 
01031 {
01032     int ret = stat(path, pst);
01033     if (ret < 0 && !to_be_ignored(errno))
01034         sys_warning(path);
01035 
01036     return ret;
01037 }
01038 
01039 static int
01040 do_lstat(const char *path, struct stat *pst, int flags)
01041 {
01042     int ret = lstat(path, pst);
01043     if (ret < 0 && !to_be_ignored(errno))
01044         sys_warning(path);
01045 
01046     return ret;
01047 }
01048 
01049 static DIR *
01050 do_opendir(const char *path, int flags, rb_encoding *enc)
01051 {
01052     DIR *dirp;
01053 #ifdef _WIN32
01054     volatile VALUE tmp;
01055     if (enc != rb_usascii_encoding() &&
01056         enc != rb_ascii8bit_encoding() &&
01057         enc != rb_utf8_encoding()) {
01058         tmp = rb_enc_str_new(path, strlen(path), enc);
01059         tmp = rb_str_encode_ospath(tmp);
01060         path = RSTRING_PTR(tmp);
01061     }
01062 #endif
01063     dirp = opendir(path);
01064     if (dirp == NULL && !to_be_ignored(errno))
01065         sys_warning(path);
01066 
01067     return dirp;
01068 }
01069 
01070 /* Return nonzero if S has any special globbing chars in it.  */
01071 static int
01072 has_magic(const char *p, const char *pend, int flags, rb_encoding *enc)
01073 {
01074     const int escape = !(flags & FNM_NOESCAPE);
01075     const int nocase = flags & FNM_CASEFOLD;
01076 
01077     register char c;
01078 
01079     while (p < pend && (c = *p++) != 0) {
01080         switch (c) {
01081           case '*':
01082           case '?':
01083           case '[':
01084             return 1;
01085 
01086           case '\\':
01087             if (escape && !(c = *p++))
01088                 return 0;
01089             continue;
01090 
01091           default:
01092             if (!FNM_SYSCASE && ISALPHA(c) && nocase)
01093                 return 1;
01094         }
01095 
01096         p = Next(p-1, pend, enc);
01097     }
01098 
01099     return 0;
01100 }
01101 
01102 /* Find separator in globbing pattern. */
01103 static char *
01104 find_dirsep(const char *p, const char *pend, int flags, rb_encoding *enc)
01105 {
01106     const int escape = !(flags & FNM_NOESCAPE);
01107 
01108     register char c;
01109     int open = 0;
01110 
01111     while ((c = *p++) != 0) {
01112         switch (c) {
01113           case '[':
01114             open = 1;
01115             continue;
01116           case ']':
01117             open = 0;
01118             continue;
01119 
01120           case '/':
01121             if (!open)
01122                 return (char *)p-1;
01123             continue;
01124 
01125           case '\\':
01126             if (escape && !(c = *p++))
01127                 return (char *)p-1;
01128             continue;
01129         }
01130 
01131         p = Next(p-1, pend, enc);
01132     }
01133 
01134     return (char *)p-1;
01135 }
01136 
01137 /* Remove escaping backslashes */
01138 static void
01139 remove_backslashes(char *p, rb_encoding *enc)
01140 {
01141     register const char *pend = p + strlen(p);
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 
01162 /* Globing pattern */
01163 enum glob_pattern_type { PLAIN, MAGICAL, RECURSIVE, MATCH_ALL, MATCH_DIR };
01164 
01165 struct glob_pattern {
01166     char *str;
01167     enum glob_pattern_type type;
01168     struct glob_pattern *next;
01169 };
01170 
01171 static void glob_free_pattern(struct glob_pattern *list);
01172 
01173 static struct glob_pattern *
01174 glob_make_pattern(const char *p, const char *e, int flags, rb_encoding *enc)
01175 {
01176     struct glob_pattern *list, *tmp, **tail = &list;
01177     int dirsep = 0; /* pattern is terminated with '/' */
01178 
01179     while (p < e && *p) {
01180         tmp = GLOB_ALLOC(struct glob_pattern);
01181         if (!tmp) goto error;
01182         if (p[0] == '*' && p[1] == '*' && p[2] == '/') {
01183             /* fold continuous RECURSIVEs (needed in glob_helper) */
01184             do { p += 3; while (*p == '/') p++; } while (p[0] == '*' && p[1] == '*' && p[2] == '/');
01185             tmp->type = RECURSIVE;
01186             tmp->str = 0;
01187             dirsep = 1;
01188         }
01189         else {
01190             const char *m = find_dirsep(p, e, flags, enc);
01191             int magic = has_magic(p, m, flags, enc);
01192             char *buf;
01193 
01194             if (!magic && *m) {
01195                 const char *m2;
01196                 while (!has_magic(m+1, m2 = find_dirsep(m+1, e, flags, enc), flags, enc) &&
01197                        *m2) {
01198                     m = m2;
01199                 }
01200             }
01201             buf = GLOB_ALLOC_N(char, m-p+1);
01202             if (!buf) {
01203                 GLOB_FREE(tmp);
01204                 goto error;
01205             }
01206             memcpy(buf, p, m-p);
01207             buf[m-p] = '\0';
01208             tmp->type = magic ? MAGICAL : PLAIN;
01209             tmp->str = buf;
01210             if (*m) {
01211                 dirsep = 1;
01212                 p = m + 1;
01213             }
01214             else {
01215                 dirsep = 0;
01216                 p = m;
01217             }
01218         }
01219         *tail = tmp;
01220         tail = &tmp->next;
01221     }
01222 
01223     tmp = GLOB_ALLOC(struct glob_pattern);
01224     if (!tmp) {
01225       error:
01226         *tail = 0;
01227         glob_free_pattern(list);
01228         return 0;
01229     }
01230     tmp->type = dirsep ? MATCH_DIR : MATCH_ALL;
01231     tmp->str = 0;
01232     *tail = tmp;
01233     tmp->next = 0;
01234 
01235     return list;
01236 }
01237 
01238 static void
01239 glob_free_pattern(struct glob_pattern *list)
01240 {
01241     while (list) {
01242         struct glob_pattern *tmp = list;
01243         list = list->next;
01244         if (tmp->str)
01245             GLOB_FREE(tmp->str);
01246         GLOB_FREE(tmp);
01247     }
01248 }
01249 
01250 static char *
01251 join_path(const char *path, int dirsep, const char *name)
01252 {
01253     long len = strlen(path);
01254     long len2 = strlen(name)+(dirsep?1:0)+1;
01255     char *buf = GLOB_ALLOC_N(char, len+len2);
01256 
01257     if (!buf) return 0;
01258     memcpy(buf, path, len);
01259     if (dirsep) {
01260         buf[len++] = '/';
01261     }
01262     buf[len] = '\0';
01263     strlcat(buf+len, name, len2);
01264     return buf;
01265 }
01266 
01267 enum answer { YES, NO, UNKNOWN };
01268 
01269 #ifndef S_ISDIR
01270 #   define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
01271 #endif
01272 
01273 #ifndef S_ISLNK
01274 #  ifndef S_IFLNK
01275 #    define S_ISLNK(m) (0)
01276 #  else
01277 #    define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
01278 #  endif
01279 #endif
01280 
01281 struct glob_args {
01282     void (*func)(const char *, VALUE, void *);
01283     const char *path;
01284     VALUE value;
01285     rb_encoding *enc;
01286 };
01287 
01288 static VALUE
01289 glob_func_caller(VALUE val)
01290 {
01291     struct glob_args *args = (struct glob_args *)val;
01292 
01293     (*args->func)(args->path, args->value, args->enc);
01294     return Qnil;
01295 }
01296 
01297 #define glob_call_func(func, path, arg, enc) (*(func))((path), (arg), (enc))
01298 
01299 static int
01300 glob_helper(
01301     const char *path,
01302     int dirsep, /* '/' should be placed before appending child entry's name to 'path'. */
01303     enum answer exist, /* Does 'path' indicate an existing entry? */
01304     enum answer isdir, /* Does 'path' indicate a directory or a symlink to a directory? */
01305     struct glob_pattern **beg,
01306     struct glob_pattern **end,
01307     int flags,
01308     ruby_glob_func *func,
01309     VALUE arg,
01310     rb_encoding *enc)
01311 {
01312     struct stat st;
01313     int status = 0;
01314     struct glob_pattern **cur, **new_beg, **new_end;
01315     int plain = 0, magical = 0, recursive = 0, match_all = 0, match_dir = 0;
01316     int escape = !(flags & FNM_NOESCAPE);
01317 
01318     for (cur = beg; cur < end; ++cur) {
01319         struct glob_pattern *p = *cur;
01320         if (p->type == RECURSIVE) {
01321             recursive = 1;
01322             p = p->next;
01323         }
01324         switch (p->type) {
01325           case PLAIN:
01326             plain = 1;
01327             break;
01328           case MAGICAL:
01329             magical = 1;
01330             break;
01331           case MATCH_ALL:
01332             match_all = 1;
01333             break;
01334           case MATCH_DIR:
01335             match_dir = 1;
01336             break;
01337           case RECURSIVE:
01338             rb_bug("continuous RECURSIVEs");
01339         }
01340     }
01341 
01342     if (*path) {
01343         if (match_all && exist == UNKNOWN) {
01344             if (do_lstat(path, &st, flags) == 0) {
01345                 exist = YES;
01346                 isdir = S_ISDIR(st.st_mode) ? YES : S_ISLNK(st.st_mode) ? UNKNOWN : NO;
01347             }
01348             else {
01349                 exist = NO;
01350                 isdir = NO;
01351             }
01352         }
01353         if (match_dir && isdir == UNKNOWN) {
01354             if (do_stat(path, &st, flags) == 0) {
01355                 exist = YES;
01356                 isdir = S_ISDIR(st.st_mode) ? YES : NO;
01357             }
01358             else {
01359                 exist = NO;
01360                 isdir = NO;
01361             }
01362         }
01363         if (match_all && exist == YES) {
01364             status = glob_call_func(func, path, arg, enc);
01365             if (status) return status;
01366         }
01367         if (match_dir && isdir == YES) {
01368             char *tmp = join_path(path, dirsep, "");
01369             if (!tmp) return -1;
01370             status = glob_call_func(func, tmp, arg, enc);
01371             GLOB_FREE(tmp);
01372             if (status) return status;
01373         }
01374     }
01375 
01376     if (exist == NO || isdir == NO) return 0;
01377 
01378     if (magical || recursive) {
01379         struct dirent *dp;
01380         DIR *dirp;
01381         IF_HAVE_READDIR_R(DEFINE_STRUCT_DIRENT entry);
01382         dirp = do_opendir(*path ? path : ".", flags, enc);
01383         if (dirp == NULL) return 0;
01384 
01385         while (READDIR(dirp, enc, &STRUCT_DIRENT(entry), dp)) {
01386             char *buf = join_path(path, dirsep, dp->d_name);
01387             enum answer new_isdir = UNKNOWN;
01388 
01389             if (!buf) {
01390                 status = -1;
01391                 break;
01392             }
01393             if (recursive && strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0
01394                 && fnmatch("*", rb_usascii_encoding(), dp->d_name, flags) == 0) {
01395 #ifndef _WIN32
01396                 if (do_lstat(buf, &st, flags) == 0)
01397                     new_isdir = S_ISDIR(st.st_mode) ? YES : S_ISLNK(st.st_mode) ? UNKNOWN : NO;
01398                 else
01399                     new_isdir = NO;
01400 #else
01401                 new_isdir = dp->d_isdir ? (!dp->d_isrep ? YES : UNKNOWN) : NO;
01402 #endif
01403             }
01404 
01405             new_beg = new_end = GLOB_ALLOC_N(struct glob_pattern *, (end - beg) * 2);
01406             if (!new_beg) {
01407                 GLOB_FREE(buf);
01408                 status = -1;
01409                 break;
01410             }
01411 
01412             for (cur = beg; cur < end; ++cur) {
01413                 struct glob_pattern *p = *cur;
01414                 if (p->type == RECURSIVE) {
01415                     if (new_isdir == YES) /* not symlink but real directory */
01416                         *new_end++ = p; /* append recursive pattern */
01417                     p = p->next; /* 0 times recursion */
01418                 }
01419                 if (p->type == PLAIN || p->type == MAGICAL) {
01420                     if (fnmatch(p->str, enc, dp->d_name, flags) == 0)
01421                         *new_end++ = p->next;
01422                 }
01423             }
01424 
01425             status = glob_helper(buf, 1, YES, new_isdir, new_beg, new_end,
01426                                  flags, func, arg, enc);
01427             GLOB_FREE(buf);
01428             GLOB_FREE(new_beg);
01429             if (status) break;
01430         }
01431 
01432         closedir(dirp);
01433     }
01434     else if (plain) {
01435         struct glob_pattern **copy_beg, **copy_end, **cur2;
01436 
01437         copy_beg = copy_end = GLOB_ALLOC_N(struct glob_pattern *, end - beg);
01438         if (!copy_beg) return -1;
01439         for (cur = beg; cur < end; ++cur)
01440             *copy_end++ = (*cur)->type == PLAIN ? *cur : 0;
01441 
01442         for (cur = copy_beg; cur < copy_end; ++cur) {
01443             if (*cur) {
01444                 char *buf;
01445                 char *name;
01446                 size_t len = strlen((*cur)->str) + 1;
01447                 name = GLOB_ALLOC_N(char, len);
01448                 if (!name) {
01449                     status = -1;
01450                     break;
01451                 }
01452                 memcpy(name, (*cur)->str, len);
01453                 if (escape) remove_backslashes(name, enc);
01454 
01455                 new_beg = new_end = GLOB_ALLOC_N(struct glob_pattern *, end - beg);
01456                 if (!new_beg) {
01457                     GLOB_FREE(name);
01458                     status = -1;
01459                     break;
01460                 }
01461                 *new_end++ = (*cur)->next;
01462                 for (cur2 = cur + 1; cur2 < copy_end; ++cur2) {
01463                     if (*cur2 && fnmatch((*cur2)->str, enc, name, flags) == 0) {
01464                         *new_end++ = (*cur2)->next;
01465                         *cur2 = 0;
01466                     }
01467                 }
01468 
01469                 buf = join_path(path, dirsep, name);
01470                 GLOB_FREE(name);
01471                 if (!buf) {
01472                     GLOB_FREE(new_beg);
01473                     status = -1;
01474                     break;
01475                 }
01476                 status = glob_helper(buf, 1, UNKNOWN, UNKNOWN, new_beg,
01477                                      new_end, flags, func, arg, enc);
01478                 GLOB_FREE(buf);
01479                 GLOB_FREE(new_beg);
01480                 if (status) break;
01481             }
01482         }
01483 
01484         GLOB_FREE(copy_beg);
01485     }
01486 
01487     return status;
01488 }
01489 
01490 static int
01491 ruby_glob0(const char *path, int flags, ruby_glob_func *func, VALUE arg, rb_encoding *enc)
01492 {
01493     struct glob_pattern *list;
01494     const char *root, *start;
01495     char *buf;
01496     size_t n;
01497     int status;
01498 
01499     start = root = path;
01500     flags |= FNM_SYSCASE;
01501 #if defined DOSISH
01502     root = rb_enc_path_skip_prefix(root, root + strlen(root), enc);
01503 #endif
01504 
01505     if (root && *root == '/') root++;
01506 
01507     n = root - start;
01508     buf = GLOB_ALLOC_N(char, n + 1);
01509     if (!buf) return -1;
01510     MEMCPY(buf, start, char, n);
01511     buf[n] = '\0';
01512 
01513     list = glob_make_pattern(root, root + strlen(root), flags, enc);
01514     if (!list) {
01515         GLOB_FREE(buf);
01516         return -1;
01517     }
01518     status = glob_helper(buf, 0, UNKNOWN, UNKNOWN, &list, &list + 1, flags, func, arg, enc);
01519     glob_free_pattern(list);
01520     GLOB_FREE(buf);
01521 
01522     return status;
01523 }
01524 
01525 int
01526 ruby_glob(const char *path, int flags, ruby_glob_func *func, VALUE arg)
01527 {
01528     return ruby_glob0(path, flags & ~GLOB_VERBOSE, func, arg,
01529                       rb_ascii8bit_encoding());
01530 }
01531 
01532 static int
01533 rb_glob_caller(const char *path, VALUE a, void *enc)
01534 {
01535     int status;
01536     struct glob_args *args = (struct glob_args *)a;
01537 
01538     args->path = path;
01539     rb_protect(glob_func_caller, a, &status);
01540     return status;
01541 }
01542 
01543 static int
01544 rb_glob2(const char *path, int flags,
01545          void (*func)(const char *, VALUE, void *), VALUE arg,
01546          rb_encoding* enc)
01547 {
01548     struct glob_args args;
01549 
01550     args.func = func;
01551     args.value = arg;
01552     args.enc = enc;
01553 
01554     if (flags & FNM_SYSCASE) {
01555         rb_warning("Dir.glob() ignores File::FNM_CASEFOLD");
01556     }
01557 
01558     return ruby_glob0(path, flags | GLOB_VERBOSE, rb_glob_caller, (VALUE)&args,
01559                       enc);
01560 }
01561 
01562 void
01563 rb_glob(const char *path, void (*func)(const char *, VALUE, void *), VALUE arg)
01564 {
01565     int status = rb_glob2(path, 0, func, arg, rb_ascii8bit_encoding());
01566     if (status) GLOB_JUMP_TAG(status);
01567 }
01568 
01569 static void
01570 push_pattern(const char *path, VALUE ary, void *enc)
01571 {
01572     rb_ary_push(ary, rb_external_str_new_with_enc(path, strlen(path), enc));
01573 }
01574 
01575 static int
01576 ruby_brace_expand(const char *str, int flags, ruby_glob_func *func, VALUE arg,
01577                   rb_encoding *enc)
01578 {
01579     const int escape = !(flags & FNM_NOESCAPE);
01580     const char *p = str;
01581     const char *pend = p + strlen(p);
01582     const char *s = p;
01583     const char *lbrace = 0, *rbrace = 0;
01584     int nest = 0, status = 0;
01585 
01586     while (*p) {
01587         if (*p == '{' && nest++ == 0) {
01588             lbrace = p;
01589         }
01590         if (*p == '}' && --nest <= 0) {
01591             rbrace = p;
01592             break;
01593         }
01594         if (*p == '\\' && escape) {
01595             if (!*++p) break;
01596         }
01597         Inc(p, pend, enc);
01598     }
01599 
01600     if (lbrace && rbrace) {
01601         size_t len = strlen(s) + 1;
01602         char *buf = GLOB_ALLOC_N(char, len);
01603         long shift;
01604 
01605         if (!buf) return -1;
01606         memcpy(buf, s, lbrace-s);
01607         shift = (lbrace-s);
01608         p = lbrace;
01609         while (p < rbrace) {
01610             const char *t = ++p;
01611             nest = 0;
01612             while (p < rbrace && !(*p == ',' && nest == 0)) {
01613                 if (*p == '{') nest++;
01614                 if (*p == '}') nest--;
01615                 if (*p == '\\' && escape) {
01616                     if (++p == rbrace) break;
01617                 }
01618                 Inc(p, pend, enc);
01619             }
01620             memcpy(buf+shift, t, p-t);
01621             strlcpy(buf+shift+(p-t), rbrace+1, len-(shift+(p-t)));
01622             status = ruby_brace_expand(buf, flags, func, arg, enc);
01623             if (status) break;
01624         }
01625         GLOB_FREE(buf);
01626     }
01627     else if (!lbrace && !rbrace) {
01628         status = (*func)(s, arg, enc);
01629     }
01630 
01631     return status;
01632 }
01633 
01634 struct brace_args {
01635     ruby_glob_func *func;
01636     VALUE value;
01637     int flags;
01638 };
01639 
01640 static int
01641 glob_brace(const char *path, VALUE val, void *enc)
01642 {
01643     struct brace_args *arg = (struct brace_args *)val;
01644 
01645     return ruby_glob0(path, arg->flags, arg->func, arg->value, enc);
01646 }
01647 
01648 static int
01649 ruby_brace_glob0(const char *str, int flags, ruby_glob_func *func, VALUE arg,
01650                  rb_encoding* enc)
01651 {
01652     struct brace_args args;
01653 
01654     args.func = func;
01655     args.value = arg;
01656     args.flags = flags;
01657     return ruby_brace_expand(str, flags, glob_brace, (VALUE)&args, enc);
01658 }
01659 
01660 int
01661 ruby_brace_glob(const char *str, int flags, ruby_glob_func *func, VALUE arg)
01662 {
01663     return ruby_brace_glob0(str, flags & ~GLOB_VERBOSE, func, arg,
01664                             rb_ascii8bit_encoding());
01665 }
01666 
01667 int
01668 ruby_brace_glob_with_enc(const char *str, int flags, ruby_glob_func *func, VALUE arg, rb_encoding *enc)
01669 {
01670     return ruby_brace_glob0(str, flags & ~GLOB_VERBOSE, func, arg, enc);
01671 }
01672 
01673 static int
01674 push_glob(VALUE ary, VALUE str, int flags)
01675 {
01676     struct glob_args args;
01677     rb_encoding *enc = rb_enc_get(str);
01678 
01679     if (enc == rb_usascii_encoding()) enc = rb_filesystem_encoding();
01680     args.func = push_pattern;
01681     args.value = ary;
01682     args.enc = enc;
01683 
01684     RB_GC_GUARD(str);
01685     return ruby_brace_glob0(RSTRING_PTR(str), flags | GLOB_VERBOSE,
01686                             rb_glob_caller, (VALUE)&args, enc);
01687 }
01688 
01689 static VALUE
01690 rb_push_glob(VALUE str, int flags) /* '\0' is delimiter */
01691 {
01692     long offset = 0;
01693     VALUE ary;
01694 
01695     GlobPathValue(str, TRUE);
01696     ary = rb_ary_new();
01697 
01698     while (offset < RSTRING_LEN(str)) {
01699         char *p, *pend;
01700         int status;
01701         p = RSTRING_PTR(str) + offset;
01702         status = push_glob(ary, rb_enc_str_new(p, strlen(p), rb_enc_get(str)),
01703                            flags);
01704         if (status) GLOB_JUMP_TAG(status);
01705         if (offset >= RSTRING_LEN(str)) break;
01706         p += strlen(p) + 1;
01707         pend = RSTRING_PTR(str) + RSTRING_LEN(str);
01708         while (p < pend && !*p)
01709             p++;
01710         offset = p - RSTRING_PTR(str);
01711     }
01712 
01713     return ary;
01714 }
01715 
01716 static VALUE
01717 dir_globs(long argc, VALUE *argv, int flags)
01718 {
01719     VALUE ary = rb_ary_new();
01720     long i;
01721 
01722     for (i = 0; i < argc; ++i) {
01723         int status;
01724         VALUE str = argv[i];
01725         GlobPathValue(str, TRUE);
01726         status = push_glob(ary, str, flags);
01727         if (status) GLOB_JUMP_TAG(status);
01728     }
01729 
01730     return ary;
01731 }
01732 
01733 /*
01734  *  call-seq:
01735  *     Dir[ array ]                 -> array
01736  *     Dir[ string [, string ...] ] -> array
01737  *
01738  *  Equivalent to calling
01739  *  <code>Dir.glob(</code><i>array,</i><code>0)</code> and
01740  *  <code>Dir.glob([</code><i>string,...</i><code>],0)</code>.
01741  *
01742  */
01743 static VALUE
01744 dir_s_aref(int argc, VALUE *argv, VALUE obj)
01745 {
01746     if (argc == 1) {
01747         return rb_push_glob(argv[0], 0);
01748     }
01749     return dir_globs(argc, argv, 0);
01750 }
01751 
01752 /*
01753  *  call-seq:
01754  *     Dir.glob( pattern, [flags] ) -> array
01755  *     Dir.glob( pattern, [flags] ) {| filename | block }  -> nil
01756  *
01757  *  Returns the filenames found by expanding <i>pattern</i> which is
01758  *  an +Array+ of the patterns or the pattern +String+, either as an
01759  *  <i>array</i> or as parameters to the block. Note that this pattern
01760  *  is not a regexp (it's closer to a shell glob). See
01761  *  <code>File::fnmatch</code> for the meaning of the <i>flags</i>
01762  *  parameter. Note that case sensitivity depends on your system (so
01763  *  <code>File::FNM_CASEFOLD</code> is ignored), as does the order
01764  *  in which the results are returned.
01765  *
01766  *  <code>*</code>::        Matches any file. Can be restricted by
01767  *                          other values in the glob. <code>*</code>
01768  *                          will match all files; <code>c*</code> will
01769  *                          match all files beginning with
01770  *                          <code>c</code>; <code>*c</code> will match
01771  *                          all files ending with <code>c</code>; and
01772  *                          <code>\*c\*</code> will match all files that
01773  *                          have <code>c</code> in them (including at
01774  *                          the beginning or end). Equivalent to
01775  *                          <code>/ .* /x</code> in regexp. Note, this
01776  *                          will not match Unix-like hidden files (dotfiles).
01777  *                          In order to include those in the match results,
01778  *                          you must use something like "{*,.*}".
01779  *  <code>**</code>::       Matches directories recursively.
01780  *  <code>?</code>::        Matches any one character. Equivalent to
01781  *                          <code>/.{1}/</code> in regexp.
01782  *  <code>[set]</code>::    Matches any one character in +set+.
01783  *                          Behaves exactly like character sets in
01784  *                          Regexp, including set negation
01785  *                          (<code>[^a-z]</code>).
01786  *  <code>{p,q}</code>::    Matches either literal <code>p</code> or
01787  *                          literal <code>q</code>. Matching literals
01788  *                          may be more than one character in length.
01789  *                          More than two literals may be specified.
01790  *                          Equivalent to pattern alternation in
01791  *                          regexp.
01792  *  <code></code>::        Escapes the next metacharacter.
01793  *                          Note that this means you cannot use backslash in windows
01794  *                          as part of a glob, i.e. Dir["c:\\foo*"] will not work
01795  *                          use Dir["c:/foo*"] instead
01796  *
01797  *     Dir["config.?"]                     #=> ["config.h"]
01798  *     Dir.glob("config.?")                #=> ["config.h"]
01799  *     Dir.glob("*.[a-z][a-z]")            #=> ["main.rb"]
01800  *     Dir.glob("*.[^r]*")                 #=> ["config.h"]
01801  *     Dir.glob("*.{rb,h}")                #=> ["main.rb", "config.h"]
01802  *     Dir.glob("*")                       #=> ["config.h", "main.rb"]
01803  *     Dir.glob("*", File::FNM_DOTMATCH)   #=> [".", "..", "config.h", "main.rb"]
01804  *
01805  *     rbfiles = File.join("**", "*.rb")
01806  *     Dir.glob(rbfiles)                   #=> ["main.rb",
01807  *                                         #    "lib/song.rb",
01808  *                                         #    "lib/song/karaoke.rb"]
01809  *     libdirs = File.join("**", "lib")
01810  *     Dir.glob(libdirs)                   #=> ["lib"]
01811  *
01812  *     librbfiles = File.join("**", "lib", "**", "*.rb")
01813  *     Dir.glob(librbfiles)                #=> ["lib/song.rb",
01814  *                                         #    "lib/song/karaoke.rb"]
01815  *
01816  *     librbfiles = File.join("**", "lib", "*.rb")
01817  *     Dir.glob(librbfiles)                #=> ["lib/song.rb"]
01818  */
01819 static VALUE
01820 dir_s_glob(int argc, VALUE *argv, VALUE obj)
01821 {
01822     VALUE str, rflags, ary;
01823     int flags;
01824 
01825     if (rb_scan_args(argc, argv, "11", &str, &rflags) == 2)
01826         flags = NUM2INT(rflags);
01827     else
01828         flags = 0;
01829 
01830     ary = rb_check_array_type(str);
01831     if (NIL_P(ary)) {
01832         ary = rb_push_glob(str, flags);
01833     }
01834     else {
01835         volatile VALUE v = ary;
01836         ary = dir_globs(RARRAY_LEN(v), RARRAY_PTR(v), flags);
01837     }
01838 
01839     if (rb_block_given_p()) {
01840         rb_ary_each(ary);
01841         return Qnil;
01842     }
01843     return ary;
01844 }
01845 
01846 static VALUE
01847 dir_open_dir(int argc, VALUE *argv)
01848 {
01849     VALUE dir = rb_funcall2(rb_cDir, rb_intern("open"), argc, argv);
01850     struct dir_data *dirp;
01851 
01852     TypedData_Get_Struct(dir, struct dir_data, &dir_data_type, dirp);
01853     return dir;
01854 }
01855 
01856 
01857 /*
01858  *  call-seq:
01859  *     Dir.foreach( dirname ) {| filename | block }  -> nil
01860  *     Dir.foreach( dirname )                        -> an_enumerator
01861  *
01862  *  Calls the block once for each entry in the named directory, passing
01863  *  the filename of each entry as a parameter to the block.
01864  *
01865  *  If no block is given, an enumerator is returned instead.
01866  *
01867  *     Dir.foreach("testdir") {|x| puts "Got #{x}" }
01868  *
01869  *  <em>produces:</em>
01870  *
01871  *     Got .
01872  *     Got ..
01873  *     Got config.h
01874  *     Got main.rb
01875  *
01876  */
01877 static VALUE
01878 dir_foreach(int argc, VALUE *argv, VALUE io)
01879 {
01880     VALUE dir;
01881 
01882     RETURN_ENUMERATOR(io, argc, argv);
01883     dir = dir_open_dir(argc, argv);
01884     rb_ensure(dir_each, dir, dir_close, dir);
01885     return Qnil;
01886 }
01887 
01888 /*
01889  *  call-seq:
01890  *     Dir.entries( dirname ) -> array
01891  *
01892  *  Returns an array containing all of the filenames in the given
01893  *  directory. Will raise a <code>SystemCallError</code> if the named
01894  *  directory doesn't exist.
01895  *
01896  *     Dir.entries("testdir")   #=> [".", "..", "config.h", "main.rb"]
01897  *
01898  */
01899 static VALUE
01900 dir_entries(int argc, VALUE *argv, VALUE io)
01901 {
01902     VALUE dir;
01903 
01904     dir = dir_open_dir(argc, argv);
01905     return rb_ensure(rb_Array, dir, dir_close, dir);
01906 }
01907 
01908 /*
01909  *  call-seq:
01910  *     File.fnmatch( pattern, path, [flags] ) -> (true or false)
01911  *     File.fnmatch?( pattern, path, [flags] ) -> (true or false)
01912  *
01913  *  Returns true if <i>path</i> matches against <i>pattern</i> The
01914  *  pattern is not a regular expression; instead it follows rules
01915  *  similar to shell filename globbing. It may contain the following
01916  *  metacharacters:
01917  *
01918  *  <code>*</code>::        Matches any file. Can be restricted by
01919  *                          other values in the glob. <code>*</code>
01920  *                          will match all files; <code>c*</code> will
01921  *                          match all files beginning with
01922  *                          <code>c</code>; <code>*c</code> will match
01923  *                          all files ending with <code>c</code>; and
01924  *                          <code>\*c*</code> will match all files that
01925  *                          have <code>c</code> in them (including at
01926  *                          the beginning or end). Equivalent to
01927  *                          <code>/ .* /x</code> in regexp.
01928  *  <code>**</code>::       Matches directories recursively or files
01929  *                          expansively.
01930  *  <code>?</code>::        Matches any one character. Equivalent to
01931  *                          <code>/.{1}/</code> in regexp.
01932  *  <code>[set]</code>::    Matches any one character in +set+.
01933  *                          Behaves exactly like character sets in
01934  *                          Regexp, including set negation
01935  *                          (<code>[^a-z]</code>).
01936  *  <code></code>::        Escapes the next metacharacter.
01937  *
01938  *  <i>flags</i> is a bitwise OR of the <code>FNM_xxx</code>
01939  *  parameters. The same glob pattern and flags are used by
01940  *  <code>Dir::glob</code>.
01941  *
01942  *     File.fnmatch('cat',       'cat')        #=> true  # match entire string
01943  *     File.fnmatch('cat',       'category')   #=> false # only match partial string
01944  *     File.fnmatch('c{at,ub}s', 'cats')       #=> false # { } isn't supported
01945  *
01946  *     File.fnmatch('c?t',     'cat')          #=> true  # '?' match only 1 character
01947  *     File.fnmatch('c??t',    'cat')          #=> false # ditto
01948  *     File.fnmatch('c*',      'cats')         #=> true  # '*' match 0 or more characters
01949  *     File.fnmatch('c*t',     'c/a/b/t')      #=> true  # ditto
01950  *     File.fnmatch('ca[a-z]', 'cat')          #=> true  # inclusive bracket expression
01951  *     File.fnmatch('ca[^t]',  'cat')          #=> false # exclusive bracket expression ('^' or '!')
01952  *
01953  *     File.fnmatch('cat', 'CAT')                     #=> false # case sensitive
01954  *     File.fnmatch('cat', 'CAT', File::FNM_CASEFOLD) #=> true  # case insensitive
01955  *
01956  *     File.fnmatch('?',   '/', File::FNM_PATHNAME)  #=> false # wildcard doesn't match '/' on FNM_PATHNAME
01957  *     File.fnmatch('*',   '/', File::FNM_PATHNAME)  #=> false # ditto
01958  *     File.fnmatch('[/]', '/', File::FNM_PATHNAME)  #=> false # ditto
01959  *
01960  *     File.fnmatch('\?',   '?')                       #=> true  # escaped wildcard becomes ordinary
01961  *     File.fnmatch('\a',   'a')                       #=> true  # escaped ordinary remains ordinary
01962  *     File.fnmatch('\a',   '\a', File::FNM_NOESCAPE)  #=> true  # FNM_NOESACPE makes '\' ordinary
01963  *     File.fnmatch('[\?]', '?')                       #=> true  # can escape inside bracket expression
01964  *
01965  *     File.fnmatch('*',   '.profile')                      #=> false # wildcard doesn't match leading
01966  *     File.fnmatch('*',   '.profile', File::FNM_DOTMATCH)  #=> true  # period by default.
01967  *     File.fnmatch('.*',  '.profile')                      #=> true
01968  *
01969  *     rbfiles = '**' '/' '*.rb' # you don't have to do like this. just write in single string.
01970  *     File.fnmatch(rbfiles, 'main.rb')                    #=> false
01971  *     File.fnmatch(rbfiles, './main.rb')                  #=> false
01972  *     File.fnmatch(rbfiles, 'lib/song.rb')                #=> true
01973  *     File.fnmatch('**.rb', 'main.rb')                    #=> true
01974  *     File.fnmatch('**.rb', './main.rb')                  #=> false
01975  *     File.fnmatch('**.rb', 'lib/song.rb')                #=> true
01976  *     File.fnmatch('*',           'dave/.profile')                      #=> true
01977  *
01978  *     pattern = '*' '/' '*'
01979  *     File.fnmatch(pattern, 'dave/.profile', File::FNM_PATHNAME)  #=> false
01980  *     File.fnmatch(pattern, 'dave/.profile', File::FNM_PATHNAME | File::FNM_DOTMATCH) #=> true
01981  *
01982  *     pattern = '**' '/' 'foo'
01983  *     File.fnmatch(pattern, 'a/b/c/foo', File::FNM_PATHNAME)     #=> true
01984  *     File.fnmatch(pattern, '/a/b/c/foo', File::FNM_PATHNAME)    #=> true
01985  *     File.fnmatch(pattern, 'c:/a/b/c/foo', File::FNM_PATHNAME)  #=> true
01986  *     File.fnmatch(pattern, 'a/.b/c/foo', File::FNM_PATHNAME)    #=> false
01987  *     File.fnmatch(pattern, 'a/.b/c/foo', File::FNM_PATHNAME | File::FNM_DOTMATCH) #=> true
01988  */
01989 static VALUE
01990 file_s_fnmatch(int argc, VALUE *argv, VALUE obj)
01991 {
01992     VALUE pattern, path;
01993     VALUE rflags;
01994     int flags;
01995 
01996     if (rb_scan_args(argc, argv, "21", &pattern, &path, &rflags) == 3)
01997         flags = NUM2INT(rflags);
01998     else
01999         flags = 0;
02000 
02001     StringValue(pattern);
02002     FilePathStringValue(path);
02003 
02004     if (fnmatch(RSTRING_PTR(pattern), rb_enc_get(pattern), RSTRING_PTR(path),
02005                 flags) == 0)
02006         return Qtrue;
02007 
02008     return Qfalse;
02009 }
02010 
02011 /*
02012  *  call-seq:
02013  *    Dir.home()       -> "/home/me"
02014  *    Dir.home("root") -> "/root"
02015  *
02016  *  Returns the home directory of the current user or the named user
02017  *  if given.
02018  */
02019 static VALUE
02020 dir_s_home(int argc, VALUE *argv, VALUE obj)
02021 {
02022     VALUE user;
02023     const char *u = 0;
02024 
02025     rb_scan_args(argc, argv, "01", &user);
02026     if (!NIL_P(user)) {
02027         SafeStringValue(user);
02028         u = StringValueCStr(user);
02029     }
02030     return rb_home_dir(u, rb_str_new(0, 0));
02031 }
02032 
02033 /*
02034  *  Objects of class <code>Dir</code> are directory streams representing
02035  *  directories in the underlying file system. They provide a variety of
02036  *  ways to list directories and their contents. See also
02037  *  <code>File</code>.
02038  *
02039  *  The directory used in these examples contains the two regular files
02040  *  (<code>config.h</code> and <code>main.rb</code>), the parent
02041  *  directory (<code>..</code>), and the directory itself
02042  *  (<code>.</code>).
02043  */
02044 void
02045 Init_Dir(void)
02046 {
02047     rb_cDir = rb_define_class("Dir", rb_cObject);
02048 
02049     rb_include_module(rb_cDir, rb_mEnumerable);
02050 
02051     rb_define_alloc_func(rb_cDir, dir_s_alloc);
02052     rb_define_singleton_method(rb_cDir, "open", dir_s_open, -1);
02053     rb_define_singleton_method(rb_cDir, "foreach", dir_foreach, -1);
02054     rb_define_singleton_method(rb_cDir, "entries", dir_entries, -1);
02055 
02056     rb_define_method(rb_cDir,"initialize", dir_initialize, -1);
02057     rb_define_method(rb_cDir,"path", dir_path, 0);
02058     rb_define_method(rb_cDir,"to_path", dir_path, 0);
02059     rb_define_method(rb_cDir,"inspect", dir_inspect, 0);
02060     rb_define_method(rb_cDir,"read", dir_read, 0);
02061     rb_define_method(rb_cDir,"each", dir_each, 0);
02062     rb_define_method(rb_cDir,"rewind", dir_rewind, 0);
02063     rb_define_method(rb_cDir,"tell", dir_tell, 0);
02064     rb_define_method(rb_cDir,"seek", dir_seek, 1);
02065     rb_define_method(rb_cDir,"pos", dir_tell, 0);
02066     rb_define_method(rb_cDir,"pos=", dir_set_pos, 1);
02067     rb_define_method(rb_cDir,"close", dir_close, 0);
02068 
02069     rb_define_singleton_method(rb_cDir,"chdir", dir_s_chdir, -1);
02070     rb_define_singleton_method(rb_cDir,"getwd", dir_s_getwd, 0);
02071     rb_define_singleton_method(rb_cDir,"pwd", dir_s_getwd, 0);
02072     rb_define_singleton_method(rb_cDir,"chroot", dir_s_chroot, 1);
02073     rb_define_singleton_method(rb_cDir,"mkdir", dir_s_mkdir, -1);
02074     rb_define_singleton_method(rb_cDir,"rmdir", dir_s_rmdir, 1);
02075     rb_define_singleton_method(rb_cDir,"delete", dir_s_rmdir, 1);
02076     rb_define_singleton_method(rb_cDir,"unlink", dir_s_rmdir, 1);
02077     rb_define_singleton_method(rb_cDir,"home", dir_s_home, -1);
02078 
02079     rb_define_singleton_method(rb_cDir,"glob", dir_s_glob, -1);
02080     rb_define_singleton_method(rb_cDir,"[]", dir_s_aref, -1);
02081     rb_define_singleton_method(rb_cDir,"exist?", rb_file_directory_p, 1); /* in file.c */
02082     rb_define_singleton_method(rb_cDir,"exists?", rb_file_directory_p, 1); /* in file.c */
02083 
02084     rb_define_singleton_method(rb_cFile,"fnmatch", file_s_fnmatch, -1);
02085     rb_define_singleton_method(rb_cFile,"fnmatch?", file_s_fnmatch, -1);
02086 
02087     rb_file_const("FNM_NOESCAPE", INT2FIX(FNM_NOESCAPE));
02088     rb_file_const("FNM_PATHNAME", INT2FIX(FNM_PATHNAME));
02089     rb_file_const("FNM_DOTMATCH", INT2FIX(FNM_DOTMATCH));
02090     rb_file_const("FNM_CASEFOLD", INT2FIX(FNM_CASEFOLD));
02091     rb_file_const("FNM_SYSCASE", INT2FIX(FNM_SYSCASE));
02092 }
02093