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