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