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