Ruby 1.9.2p136(2010-12-25revision30365)

- 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