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

Generated on Wed Sep 8 2010 21:50:19 for Ruby by  doxygen 1.7.1