• Main Page
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

dir.c

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

Generated on Thu Sep 8 2011 03:46:41 for Ruby by  doxygen 1.7.1