1/********************************************************************** 2 3 dir.c - 4 5 $Author: nagachika $ 6 created at: Wed Jan 5 09:51:01 JST 1994 7 8 Copyright (C) 1993-2007 Yukihiro Matsumoto 9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc. 10 Copyright (C) 2000 Information-technology Promotion Agency, Japan 11 12**********************************************************************/ 13 14#include "ruby/ruby.h" 15#include "ruby/encoding.h" 16#include "internal.h" 17 18#include <sys/types.h> 19#include <sys/stat.h> 20 21#ifdef HAVE_UNISTD_H 22#include <unistd.h> 23#endif 24 25#if defined HAVE_DIRENT_H && !defined _WIN32 26# include <dirent.h> 27# define NAMLEN(dirent) strlen((dirent)->d_name) 28#elif defined HAVE_DIRECT_H && !defined _WIN32 29# include <direct.h> 30# define NAMLEN(dirent) strlen((dirent)->d_name) 31#else 32# define dirent direct 33# define NAMLEN(dirent) (dirent)->d_namlen 34# if HAVE_SYS_NDIR_H 35# include <sys/ndir.h> 36# endif 37# if HAVE_SYS_DIR_H 38# include <sys/dir.h> 39# endif 40# if HAVE_NDIR_H 41# include <ndir.h> 42# endif 43# ifdef _WIN32 44# include "win32/dir.h" 45# endif 46#endif 47#if defined(__native_client__) && defined(NACL_NEWLIB) 48# include "nacl/dirent.h" 49# include "nacl/stat.h" 50#endif 51 52#include <errno.h> 53 54#ifndef HAVE_STDLIB_H 55char *getenv(); 56#endif 57 58#ifndef HAVE_STRING_H 59char *strchr(char*,char); 60#endif 61 62#include <ctype.h> 63 64#include "ruby/util.h" 65 66#if !defined HAVE_LSTAT && !defined lstat 67#define lstat stat 68#endif 69 70/* define system APIs */ 71#ifdef _WIN32 72#undef chdir 73#define chdir(p) rb_w32_uchdir(p) 74#undef mkdir 75#define mkdir(p, m) rb_w32_umkdir((p), (m)) 76#undef rmdir 77#define rmdir(p) rb_w32_urmdir(p) 78#undef opendir 79#define opendir(p) rb_w32_uopendir(p) 80#endif 81 82#define rb_sys_fail_path(path) rb_sys_fail_str(path) 83 84#define FNM_NOESCAPE 0x01 85#define FNM_PATHNAME 0x02 86#define FNM_DOTMATCH 0x04 87#define FNM_CASEFOLD 0x08 88#define FNM_EXTGLOB 0x10 89#if CASEFOLD_FILESYSTEM 90#define FNM_SYSCASE FNM_CASEFOLD 91#else 92#define FNM_SYSCASE 0 93#endif 94 95#define FNM_NOMATCH 1 96#define FNM_ERROR 2 97 98# define Next(p, e, enc) ((p)+ rb_enc_mbclen((p), (e), (enc))) 99# define Inc(p, e, enc) ((p) = Next((p), (e), (enc))) 100 101static char * 102bracket( 103 const char *p, /* pattern (next to '[') */ 104 const char *pend, 105 const char *s, /* string */ 106 const char *send, 107 int flags, 108 rb_encoding *enc) 109{ 110 const int nocase = flags & FNM_CASEFOLD; 111 const int escape = !(flags & FNM_NOESCAPE); 112 unsigned int c1, c2; 113 int r; 114 int ok = 0, not = 0; 115 116 if (p >= pend) return NULL; 117 if (*p == '!' || *p == '^') { 118 not = 1; 119 p++; 120 } 121 122 while (*p != ']') { 123 const char *t1 = p; 124 if (escape && *t1 == '\\') 125 t1++; 126 if (!*t1) 127 return NULL; 128 p = t1 + (r = rb_enc_mbclen(t1, pend, enc)); 129 if (p >= pend) return NULL; 130 if (p[0] == '-' && p[1] != ']') { 131 const char *t2 = p + 1; 132 int r2; 133 if (escape && *t2 == '\\') 134 t2++; 135 if (!*t2) 136 return NULL; 137 p = t2 + (r2 = rb_enc_mbclen(t2, pend, enc)); 138 if (ok) continue; 139 if ((r <= (send-s) && memcmp(t1, s, r) == 0) || 140 (r2 <= (send-s) && memcmp(t2, s, r2) == 0)) { 141 ok = 1; 142 continue; 143 } 144 c1 = rb_enc_codepoint(s, send, enc); 145 if (nocase) c1 = rb_enc_toupper(c1, enc); 146 c2 = rb_enc_codepoint(t1, pend, enc); 147 if (nocase) c2 = rb_enc_toupper(c2, enc); 148 if (c1 < c2) continue; 149 c2 = rb_enc_codepoint(t2, pend, enc); 150 if (nocase) c2 = rb_enc_toupper(c2, enc); 151 if (c1 > c2) continue; 152 } 153 else { 154 if (ok) continue; 155 if (r <= (send-s) && memcmp(t1, s, r) == 0) { 156 ok = 1; 157 continue; 158 } 159 if (!nocase) continue; 160 c1 = rb_enc_toupper(rb_enc_codepoint(s, send, enc), enc); 161 c2 = rb_enc_toupper(rb_enc_codepoint(p, pend, enc), enc); 162 if (c1 != c2) continue; 163 } 164 ok = 1; 165 } 166 167 return ok == not ? NULL : (char *)p + 1; 168} 169 170/* If FNM_PATHNAME is set, only path element will be matched. (upto '/' or '\0') 171 Otherwise, entire string will be matched. 172 End marker itself won't be compared. 173 And if function succeeds, *pcur reaches end marker. 174*/ 175#define UNESCAPE(p) (escape && *(p) == '\\' ? (p) + 1 : (p)) 176#define ISEND(p) (!*(p) || (pathname && *(p) == '/')) 177#define RETURN(val) return *pcur = p, *scur = s, (val); 178 179static int 180fnmatch_helper( 181 const char **pcur, /* pattern */ 182 const char **scur, /* string */ 183 int flags, 184 rb_encoding *enc) 185{ 186 const int period = !(flags & FNM_DOTMATCH); 187 const int pathname = flags & FNM_PATHNAME; 188 const int escape = !(flags & FNM_NOESCAPE); 189 const int nocase = flags & FNM_CASEFOLD; 190 191 const char *ptmp = 0; 192 const char *stmp = 0; 193 194 const char *p = *pcur; 195 const char *pend = p + strlen(p); 196 const char *s = *scur; 197 const char *send = s + strlen(s); 198 199 int r; 200 201 if (period && *s == '.' && *UNESCAPE(p) != '.') /* leading period */ 202 RETURN(FNM_NOMATCH); 203 204 while (1) { 205 switch (*p) { 206 case '*': 207 do { p++; } while (*p == '*'); 208 if (ISEND(UNESCAPE(p))) { 209 p = UNESCAPE(p); 210 RETURN(0); 211 } 212 if (ISEND(s)) 213 RETURN(FNM_NOMATCH); 214 ptmp = p; 215 stmp = s; 216 continue; 217 218 case '?': 219 if (ISEND(s)) 220 RETURN(FNM_NOMATCH); 221 p++; 222 Inc(s, send, enc); 223 continue; 224 225 case '[': { 226 const char *t; 227 if (ISEND(s)) 228 RETURN(FNM_NOMATCH); 229 if ((t = bracket(p + 1, pend, s, send, flags, enc)) != 0) { 230 p = t; 231 Inc(s, send, enc); 232 continue; 233 } 234 goto failed; 235 } 236 } 237 238 /* ordinary */ 239 p = UNESCAPE(p); 240 if (ISEND(s)) 241 RETURN(ISEND(p) ? 0 : FNM_NOMATCH); 242 if (ISEND(p)) 243 goto failed; 244 r = rb_enc_precise_mbclen(p, pend, enc); 245 if (!MBCLEN_CHARFOUND_P(r)) 246 goto failed; 247 if (r <= (send-s) && memcmp(p, s, r) == 0) { 248 p += r; 249 s += r; 250 continue; 251 } 252 if (!nocase) goto failed; 253 if (rb_enc_toupper(rb_enc_codepoint(p, pend, enc), enc) != 254 rb_enc_toupper(rb_enc_codepoint(s, send, enc), enc)) 255 goto failed; 256 p += r; 257 Inc(s, send, enc); 258 continue; 259 260 failed: /* try next '*' position */ 261 if (ptmp && stmp) { 262 p = ptmp; 263 Inc(stmp, send, enc); /* !ISEND(*stmp) */ 264 s = stmp; 265 continue; 266 } 267 RETURN(FNM_NOMATCH); 268 } 269} 270 271static int 272fnmatch( 273 const char *pattern, 274 rb_encoding *enc, 275 const char *string, 276 int flags) 277{ 278 const char *p = pattern; 279 const char *s = string; 280 const char *send = s + strlen(string); 281 const int period = !(flags & FNM_DOTMATCH); 282 const int pathname = flags & FNM_PATHNAME; 283 284 const char *ptmp = 0; 285 const char *stmp = 0; 286 287 if (pathname) { 288 while (1) { 289 if (p[0] == '*' && p[1] == '*' && p[2] == '/') { 290 do { p += 3; } while (p[0] == '*' && p[1] == '*' && p[2] == '/'); 291 ptmp = p; 292 stmp = s; 293 } 294 if (fnmatch_helper(&p, &s, flags, enc) == 0) { 295 while (*s && *s != '/') Inc(s, send, enc); 296 if (*p && *s) { 297 p++; 298 s++; 299 continue; 300 } 301 if (!*p && !*s) 302 return 0; 303 } 304 /* failed : try next recursion */ 305 if (ptmp && stmp && !(period && *stmp == '.')) { 306 while (*stmp && *stmp != '/') Inc(stmp, send, enc); 307 if (*stmp) { 308 p = ptmp; 309 stmp++; 310 s = stmp; 311 continue; 312 } 313 } 314 return FNM_NOMATCH; 315 } 316 } 317 else 318 return fnmatch_helper(&p, &s, flags, enc); 319} 320 321VALUE rb_cDir; 322 323struct dir_data { 324 DIR *dir; 325 VALUE path; 326 rb_encoding *enc; 327}; 328 329static void 330dir_mark(void *ptr) 331{ 332 struct dir_data *dir = ptr; 333 rb_gc_mark(dir->path); 334} 335 336static void 337dir_free(void *ptr) 338{ 339 struct dir_data *dir = ptr; 340 if (dir) { 341 if (dir->dir) closedir(dir->dir); 342 } 343 xfree(dir); 344} 345 346static size_t 347dir_memsize(const void *ptr) 348{ 349 return ptr ? sizeof(struct dir_data) : 0; 350} 351 352static const rb_data_type_t dir_data_type = { 353 "dir", 354 {dir_mark, dir_free, dir_memsize,}, 355}; 356 357static VALUE dir_close(VALUE); 358 359#define GlobPathValue(str, safe) \ 360 /* can contain null bytes as separators */ \ 361 (!RB_TYPE_P((str), T_STRING) ? \ 362 (void)FilePathValue(str) : \ 363 (void)(check_safe_glob((str), (safe)), \ 364 check_glob_encoding(str), (str))) 365#define check_safe_glob(str, safe) ((safe) ? rb_check_safe_obj(str) : (void)0) 366#define check_glob_encoding(str) rb_enc_check((str), rb_enc_from_encoding(rb_usascii_encoding())) 367 368static VALUE 369dir_s_alloc(VALUE klass) 370{ 371 struct dir_data *dirp; 372 VALUE obj = TypedData_Make_Struct(klass, struct dir_data, &dir_data_type, dirp); 373 374 dirp->dir = NULL; 375 dirp->path = Qnil; 376 dirp->enc = NULL; 377 378 return obj; 379} 380 381/* 382 * call-seq: 383 * Dir.new( string ) -> aDir 384 * 385 * Returns a new directory object for the named directory. 386 */ 387static VALUE 388dir_initialize(int argc, VALUE *argv, VALUE dir) 389{ 390 struct dir_data *dp; 391 rb_encoding *fsenc; 392 VALUE dirname, opt, orig; 393 static VALUE sym_enc; 394 395 if (!sym_enc) { 396 sym_enc = ID2SYM(rb_intern("encoding")); 397 } 398 fsenc = rb_filesystem_encoding(); 399 400 rb_scan_args(argc, argv, "1:", &dirname, &opt); 401 402 if (!NIL_P(opt)) { 403 VALUE enc = rb_hash_aref(opt, sym_enc); 404 if (!NIL_P(enc)) { 405 fsenc = rb_to_encoding(enc); 406 } 407 } 408 409 GlobPathValue(dirname, FALSE); 410 orig = rb_str_dup_frozen(dirname); 411 dirname = rb_str_encode_ospath(dirname); 412 dirname = rb_str_dup_frozen(dirname); 413 414 TypedData_Get_Struct(dir, struct dir_data, &dir_data_type, dp); 415 if (dp->dir) closedir(dp->dir); 416 dp->dir = NULL; 417 dp->path = Qnil; 418 dp->enc = fsenc; 419 dp->dir = opendir(RSTRING_PTR(dirname)); 420 if (dp->dir == NULL) { 421 if (errno == EMFILE || errno == ENFILE) { 422 rb_gc(); 423 dp->dir = opendir(RSTRING_PTR(dirname)); 424 } 425 if (dp->dir == NULL) { 426 rb_sys_fail_path(orig); 427 } 428 } 429 dp->path = orig; 430 431 return dir; 432} 433 434/* 435 * call-seq: 436 * Dir.open( string ) -> aDir 437 * Dir.open( string ) {| aDir | block } -> anObject 438 * 439 * With no block, <code>open</code> is a synonym for 440 * <code>Dir::new</code>. If a block is present, it is passed 441 * <i>aDir</i> as a parameter. The directory is closed at the end of 442 * the block, and <code>Dir::open</code> returns the value of the 443 * block. 444 */ 445static VALUE 446dir_s_open(int argc, VALUE *argv, VALUE klass) 447{ 448 struct dir_data *dp; 449 VALUE dir = TypedData_Make_Struct(klass, struct dir_data, &dir_data_type, dp); 450 451 dir_initialize(argc, argv, dir); 452 if (rb_block_given_p()) { 453 return rb_ensure(rb_yield, dir, dir_close, dir); 454 } 455 456 return dir; 457} 458 459static void 460dir_closed(void) 461{ 462 rb_raise(rb_eIOError, "closed directory"); 463} 464 465static struct dir_data * 466dir_check(VALUE dir) 467{ 468 struct dir_data *dirp; 469 if (!OBJ_UNTRUSTED(dir) && rb_safe_level() >= 4) 470 rb_raise(rb_eSecurityError, "Insecure: operation on trusted Dir"); 471 rb_check_frozen(dir); 472 dirp = rb_check_typeddata(dir, &dir_data_type); 473 if (!dirp->dir) dir_closed(); 474 return dirp; 475} 476 477#define GetDIR(obj, dirp) ((dirp) = dir_check(obj)) 478 479 480/* 481 * call-seq: 482 * dir.inspect -> string 483 * 484 * Return a string describing this Dir object. 485 */ 486static VALUE 487dir_inspect(VALUE dir) 488{ 489 struct dir_data *dirp; 490 491 TypedData_Get_Struct(dir, struct dir_data, &dir_data_type, dirp); 492 if (!NIL_P(dirp->path)) { 493 VALUE str = rb_str_new_cstr("#<"); 494 rb_str_append(str, rb_class_name(CLASS_OF(dir))); 495 rb_str_cat2(str, ":"); 496 rb_str_append(str, dirp->path); 497 rb_str_cat2(str, ">"); 498 return str; 499 } 500 return rb_funcall(dir, rb_intern("to_s"), 0, 0); 501} 502 503/* 504 * call-seq: 505 * dir.path -> string or nil 506 * 507 * Returns the path parameter passed to <em>dir</em>'s constructor. 508 * 509 * d = Dir.new("..") 510 * d.path #=> ".." 511 */ 512static VALUE 513dir_path(VALUE dir) 514{ 515 struct dir_data *dirp; 516 517 TypedData_Get_Struct(dir, struct dir_data, &dir_data_type, dirp); 518 if (NIL_P(dirp->path)) return Qnil; 519 return rb_str_dup(dirp->path); 520} 521 522#if defined HAVE_READDIR_R 523# define READDIR(dir, enc, entry, dp) (readdir_r((dir), (entry), &(dp)) == 0 && (dp) != 0) 524#elif defined _WIN32 525# define READDIR(dir, enc, entry, dp) (((dp) = rb_w32_readdir((dir), (enc))) != 0) 526#else 527# define READDIR(dir, enc, entry, dp) (((dp) = readdir(dir)) != 0) 528#endif 529#if defined HAVE_READDIR_R 530# define IF_HAVE_READDIR_R(something) something 531#else 532# define IF_HAVE_READDIR_R(something) /* nothing */ 533#endif 534 535#if defined SIZEOF_STRUCT_DIRENT_TOO_SMALL 536# include <limits.h> 537# define NAME_MAX_FOR_STRUCT_DIRENT 255 538# if defined NAME_MAX 539# if NAME_MAX_FOR_STRUCT_DIRENT < NAME_MAX 540# undef NAME_MAX_FOR_STRUCT_DIRENT 541# define NAME_MAX_FOR_STRUCT_DIRENT NAME_MAX 542# endif 543# endif 544# if defined _POSIX_NAME_MAX 545# if NAME_MAX_FOR_STRUCT_DIRENT < _POSIX_NAME_MAX 546# undef NAME_MAX_FOR_STRUCT_DIRENT 547# define NAME_MAX_FOR_STRUCT_DIRENT _POSIX_NAME_MAX 548# endif 549# endif 550# if defined _XOPEN_NAME_MAX 551# if NAME_MAX_FOR_STRUCT_DIRENT < _XOPEN_NAME_MAX 552# undef NAME_MAX_FOR_STRUCT_DIRENT 553# define NAME_MAX_FOR_STRUCT_DIRENT _XOPEN_NAME_MAX 554# endif 555# endif 556# define DEFINE_STRUCT_DIRENT \ 557 union { \ 558 struct dirent dirent; \ 559 char dummy[offsetof(struct dirent, d_name) + \ 560 NAME_MAX_FOR_STRUCT_DIRENT + 1]; \ 561 } 562# define STRUCT_DIRENT(entry) ((entry).dirent) 563#else 564# define DEFINE_STRUCT_DIRENT struct dirent 565# define STRUCT_DIRENT(entry) (entry) 566#endif 567 568/* 569 * call-seq: 570 * dir.read -> string or nil 571 * 572 * Reads the next entry from <em>dir</em> and returns it as a string. 573 * Returns <code>nil</code> at the end of the stream. 574 * 575 * d = Dir.new("testdir") 576 * d.read #=> "." 577 * d.read #=> ".." 578 * d.read #=> "config.h" 579 */ 580static VALUE 581dir_read(VALUE dir) 582{ 583 struct dir_data *dirp; 584 struct dirent *dp; 585 IF_HAVE_READDIR_R(DEFINE_STRUCT_DIRENT entry); 586 587 GetDIR(dir, dirp); 588 errno = 0; 589 if (READDIR(dirp->dir, dirp->enc, &STRUCT_DIRENT(entry), dp)) { 590 return rb_external_str_new_with_enc(dp->d_name, NAMLEN(dp), dirp->enc); 591 } 592 else { 593 if (errno != 0) rb_sys_fail(0); 594 return Qnil; /* end of stream */ 595 } 596} 597 598/* 599 * call-seq: 600 * dir.each { |filename| block } -> dir 601 * dir.each -> an_enumerator 602 * 603 * Calls the block once for each entry in this directory, passing the 604 * filename of each entry as a parameter to the block. 605 * 606 * If no block is given, an enumerator is returned instead. 607 * 608 * d = Dir.new("testdir") 609 * d.each {|x| puts "Got #{x}" } 610 * 611 * <em>produces:</em> 612 * 613 * Got . 614 * Got .. 615 * Got config.h 616 * Got main.rb 617 */ 618static VALUE 619dir_each(VALUE dir) 620{ 621 struct dir_data *dirp; 622 struct dirent *dp; 623 IF_HAVE_READDIR_R(DEFINE_STRUCT_DIRENT entry); 624 625 RETURN_ENUMERATOR(dir, 0, 0); 626 GetDIR(dir, dirp); 627 rewinddir(dirp->dir); 628 while (READDIR(dirp->dir, dirp->enc, &STRUCT_DIRENT(entry), dp)) { 629 rb_yield(rb_external_str_new_with_enc(dp->d_name, NAMLEN(dp), dirp->enc)); 630 if (dirp->dir == NULL) dir_closed(); 631 } 632 return dir; 633} 634 635#ifdef HAVE_TELLDIR 636/* 637 * call-seq: 638 * dir.pos -> integer 639 * dir.tell -> integer 640 * 641 * Returns the current position in <em>dir</em>. See also 642 * <code>Dir#seek</code>. 643 * 644 * d = Dir.new("testdir") 645 * d.tell #=> 0 646 * d.read #=> "." 647 * d.tell #=> 12 648 */ 649static VALUE 650dir_tell(VALUE dir) 651{ 652 struct dir_data *dirp; 653 long pos; 654 655 GetDIR(dir, dirp); 656 pos = telldir(dirp->dir); 657 return rb_int2inum(pos); 658} 659#else 660#define dir_tell rb_f_notimplement 661#endif 662 663#ifdef HAVE_SEEKDIR 664/* 665 * call-seq: 666 * dir.seek( integer ) -> dir 667 * 668 * Seeks to a particular location in <em>dir</em>. <i>integer</i> 669 * must be a value returned by <code>Dir#tell</code>. 670 * 671 * d = Dir.new("testdir") #=> #<Dir:0x401b3c40> 672 * d.read #=> "." 673 * i = d.tell #=> 12 674 * d.read #=> ".." 675 * d.seek(i) #=> #<Dir:0x401b3c40> 676 * d.read #=> ".." 677 */ 678static VALUE 679dir_seek(VALUE dir, VALUE pos) 680{ 681 struct dir_data *dirp; 682 long p = NUM2LONG(pos); 683 684 GetDIR(dir, dirp); 685 seekdir(dirp->dir, p); 686 return dir; 687} 688#else 689#define dir_seek rb_f_notimplement 690#endif 691 692#ifdef HAVE_SEEKDIR 693/* 694 * call-seq: 695 * dir.pos( integer ) -> integer 696 * 697 * Synonym for <code>Dir#seek</code>, but returns the position 698 * parameter. 699 * 700 * d = Dir.new("testdir") #=> #<Dir:0x401b3c40> 701 * d.read #=> "." 702 * i = d.pos #=> 12 703 * d.read #=> ".." 704 * d.pos = i #=> 12 705 * d.read #=> ".." 706 */ 707static VALUE 708dir_set_pos(VALUE dir, VALUE pos) 709{ 710 dir_seek(dir, pos); 711 return pos; 712} 713#else 714#define dir_set_pos rb_f_notimplement 715#endif 716 717/* 718 * call-seq: 719 * dir.rewind -> dir 720 * 721 * Repositions <em>dir</em> to the first entry. 722 * 723 * d = Dir.new("testdir") 724 * d.read #=> "." 725 * d.rewind #=> #<Dir:0x401b3fb0> 726 * d.read #=> "." 727 */ 728static VALUE 729dir_rewind(VALUE dir) 730{ 731 struct dir_data *dirp; 732 733 if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(dir)) { 734 rb_raise(rb_eSecurityError, "Insecure: can't close"); 735 } 736 GetDIR(dir, dirp); 737 rewinddir(dirp->dir); 738 return dir; 739} 740 741/* 742 * call-seq: 743 * dir.close -> nil 744 * 745 * Closes the directory stream. Any further attempts to access 746 * <em>dir</em> will raise an <code>IOError</code>. 747 * 748 * d = Dir.new("testdir") 749 * d.close #=> nil 750 */ 751static VALUE 752dir_close(VALUE dir) 753{ 754 struct dir_data *dirp; 755 756 GetDIR(dir, dirp); 757 closedir(dirp->dir); 758 dirp->dir = NULL; 759 760 return Qnil; 761} 762 763static void 764dir_chdir(VALUE path) 765{ 766 if (chdir(RSTRING_PTR(path)) < 0) 767 rb_sys_fail_path(path); 768} 769 770static int chdir_blocking = 0; 771static VALUE chdir_thread = Qnil; 772 773struct chdir_data { 774 VALUE old_path, new_path; 775 int done; 776}; 777 778static VALUE 779chdir_yield(struct chdir_data *args) 780{ 781 dir_chdir(args->new_path); 782 args->done = TRUE; 783 chdir_blocking++; 784 if (chdir_thread == Qnil) 785 chdir_thread = rb_thread_current(); 786 return rb_yield(args->new_path); 787} 788 789static VALUE 790chdir_restore(struct chdir_data *args) 791{ 792 if (args->done) { 793 chdir_blocking--; 794 if (chdir_blocking == 0) 795 chdir_thread = Qnil; 796 dir_chdir(args->old_path); 797 } 798 return Qnil; 799} 800 801/* 802 * call-seq: 803 * Dir.chdir( [ string] ) -> 0 804 * Dir.chdir( [ string] ) {| path | block } -> anObject 805 * 806 * Changes the current working directory of the process to the given 807 * string. When called without an argument, changes the directory to 808 * the value of the environment variable <code>HOME</code>, or 809 * <code>LOGDIR</code>. <code>SystemCallError</code> (probably 810 * <code>Errno::ENOENT</code>) if the target directory does not exist. 811 * 812 * If a block is given, it is passed the name of the new current 813 * directory, and the block is executed with that as the current 814 * directory. The original working directory is restored when the block 815 * exits. The return value of <code>chdir</code> is the value of the 816 * block. <code>chdir</code> blocks can be nested, but in a 817 * multi-threaded program an error will be raised if a thread attempts 818 * to open a <code>chdir</code> block while another thread has one 819 * open. 820 * 821 * Dir.chdir("/var/spool/mail") 822 * puts Dir.pwd 823 * Dir.chdir("/tmp") do 824 * puts Dir.pwd 825 * Dir.chdir("/usr") do 826 * puts Dir.pwd 827 * end 828 * puts Dir.pwd 829 * end 830 * puts Dir.pwd 831 * 832 * <em>produces:</em> 833 * 834 * /var/spool/mail 835 * /tmp 836 * /usr 837 * /tmp 838 * /var/spool/mail 839 */ 840static VALUE 841dir_s_chdir(int argc, VALUE *argv, VALUE obj) 842{ 843 VALUE path = Qnil; 844 845 rb_secure(2); 846 if (rb_scan_args(argc, argv, "01", &path) == 1) { 847 FilePathValue(path); 848 path = rb_str_encode_ospath(path); 849 } 850 else { 851 const char *dist = getenv("HOME"); 852 if (!dist) { 853 dist = getenv("LOGDIR"); 854 if (!dist) rb_raise(rb_eArgError, "HOME/LOGDIR not set"); 855 } 856 path = rb_str_new2(dist); 857 } 858 859 if (chdir_blocking > 0) { 860 if (!rb_block_given_p() || rb_thread_current() != chdir_thread) 861 rb_warn("conflicting chdir during another chdir block"); 862 } 863 864 if (rb_block_given_p()) { 865 struct chdir_data args; 866 867 args.old_path = rb_str_encode_ospath(rb_dir_getwd()); 868 args.new_path = path; 869 args.done = FALSE; 870 return rb_ensure(chdir_yield, (VALUE)&args, chdir_restore, (VALUE)&args); 871 } 872 dir_chdir(path); 873 874 return INT2FIX(0); 875} 876 877VALUE 878rb_dir_getwd(void) 879{ 880 char *path; 881 VALUE cwd; 882 883 rb_secure(4); 884 path = my_getcwd(); 885 cwd = rb_tainted_str_new2(path); 886 rb_enc_associate(cwd, rb_filesystem_encoding()); 887 888 xfree(path); 889 return cwd; 890} 891 892/* 893 * call-seq: 894 * Dir.getwd -> string 895 * Dir.pwd -> string 896 * 897 * Returns the path to the current working directory of this process as 898 * a string. 899 * 900 * Dir.chdir("/tmp") #=> 0 901 * Dir.getwd #=> "/tmp" 902 */ 903static VALUE 904dir_s_getwd(VALUE dir) 905{ 906 return rb_dir_getwd(); 907} 908 909static void 910check_dirname(volatile VALUE *dir) 911{ 912 VALUE d = *dir; 913 char *path, *pend; 914 long len; 915 rb_encoding *enc; 916 917 rb_secure(2); 918 FilePathValue(d); 919 enc = rb_enc_get(d); 920 RSTRING_GETMEM(d, path, len); 921 pend = path + len; 922 pend = rb_enc_path_end(rb_enc_path_skip_prefix(path, pend, enc), pend, enc); 923 if (pend - path < len) { 924 d = rb_str_subseq(d, 0, pend - path); 925 } 926 *dir = rb_str_encode_ospath(d); 927} 928 929#if defined(HAVE_CHROOT) 930/* 931 * call-seq: 932 * Dir.chroot( string ) -> 0 933 * 934 * Changes this process's idea of the file system root. Only a 935 * privileged process may make this call. Not available on all 936 * platforms. On Unix systems, see <code>chroot(2)</code> for more 937 * information. 938 */ 939static VALUE 940dir_s_chroot(VALUE dir, VALUE path) 941{ 942 check_dirname(&path); 943 if (chroot(RSTRING_PTR(path)) == -1) 944 rb_sys_fail_path(path); 945 946 return INT2FIX(0); 947} 948#else 949#define dir_s_chroot rb_f_notimplement 950#endif 951 952/* 953 * call-seq: 954 * Dir.mkdir( string [, integer] ) -> 0 955 * 956 * Makes a new directory named by <i>string</i>, with permissions 957 * specified by the optional parameter <i>anInteger</i>. The 958 * permissions may be modified by the value of 959 * <code>File::umask</code>, and are ignored on NT. Raises a 960 * <code>SystemCallError</code> if the directory cannot be created. See 961 * also the discussion of permissions in the class documentation for 962 * <code>File</code>. 963 * 964 * Dir.mkdir(File.join(Dir.home, ".foo"), 0700) #=> 0 965 * 966 */ 967static VALUE 968dir_s_mkdir(int argc, VALUE *argv, VALUE obj) 969{ 970 VALUE path, vmode; 971 int mode; 972 973 if (rb_scan_args(argc, argv, "11", &path, &vmode) == 2) { 974 mode = NUM2INT(vmode); 975 } 976 else { 977 mode = 0777; 978 } 979 980 check_dirname(&path); 981 if (mkdir(RSTRING_PTR(path), mode) == -1) 982 rb_sys_fail_path(path); 983 984 return INT2FIX(0); 985} 986 987/* 988 * call-seq: 989 * Dir.delete( string ) -> 0 990 * Dir.rmdir( string ) -> 0 991 * Dir.unlink( string ) -> 0 992 * 993 * Deletes the named directory. Raises a subclass of 994 * <code>SystemCallError</code> if the directory isn't empty. 995 */ 996static VALUE 997dir_s_rmdir(VALUE obj, VALUE dir) 998{ 999 check_dirname(&dir); 1000 if (rmdir(RSTRING_PTR(dir)) < 0) 1001 rb_sys_fail_path(dir); 1002 1003 return INT2FIX(0); 1004} 1005 1006static VALUE 1007sys_warning_1(VALUE mesg) 1008{ 1009 rb_sys_warning("%s:%s", strerror(errno), (const char *)mesg); 1010 return Qnil; 1011} 1012 1013#define GLOB_VERBOSE (1U << (sizeof(int) * CHAR_BIT - 1)) 1014#define sys_warning(val) \ 1015 (void)((flags & GLOB_VERBOSE) && rb_protect(sys_warning_1, (VALUE)(val), 0)) 1016 1017#define GLOB_ALLOC(type) ((type *)malloc(sizeof(type))) 1018#define GLOB_ALLOC_N(type, n) ((type *)malloc(sizeof(type) * (n))) 1019#define GLOB_FREE(ptr) free(ptr) 1020#define GLOB_JUMP_TAG(status) (((status) == -1) ? rb_memerror() : rb_jump_tag(status)) 1021 1022/* 1023 * ENOTDIR can be returned by stat(2) if a non-leaf element of the path 1024 * is not a directory. 1025 */ 1026#define to_be_ignored(e) ((e) == ENOENT || (e) == ENOTDIR) 1027 1028/* System call with warning */ 1029static int 1030do_stat(const char *path, struct stat *pst, int flags) 1031 1032{ 1033 int ret = stat(path, pst); 1034 if (ret < 0 && !to_be_ignored(errno)) 1035 sys_warning(path); 1036 1037 return ret; 1038} 1039 1040static int 1041do_lstat(const char *path, struct stat *pst, int flags) 1042{ 1043 int ret = lstat(path, pst); 1044 if (ret < 0 && !to_be_ignored(errno)) 1045 sys_warning(path); 1046 1047 return ret; 1048} 1049 1050static DIR * 1051do_opendir(const char *path, int flags, rb_encoding *enc) 1052{ 1053 DIR *dirp; 1054#ifdef _WIN32 1055 volatile VALUE tmp; 1056 if (enc != rb_usascii_encoding() && 1057 enc != rb_ascii8bit_encoding() && 1058 enc != rb_utf8_encoding()) { 1059 tmp = rb_enc_str_new(path, strlen(path), enc); 1060 tmp = rb_str_encode_ospath(tmp); 1061 path = RSTRING_PTR(tmp); 1062 } 1063#endif 1064 dirp = opendir(path); 1065 if (dirp == NULL && !to_be_ignored(errno)) 1066 sys_warning(path); 1067 1068 return dirp; 1069} 1070 1071/* Return nonzero if S has any special globbing chars in it. */ 1072static int 1073has_magic(const char *p, const char *pend, int flags, rb_encoding *enc) 1074{ 1075 const int escape = !(flags & FNM_NOESCAPE); 1076 const int nocase = flags & FNM_CASEFOLD; 1077 1078 register char c; 1079 1080 while (p < pend && (c = *p++) != 0) { 1081 switch (c) { 1082 case '*': 1083 case '?': 1084 case '[': 1085 return 1; 1086 1087 case '\\': 1088 if (escape && !(c = *p++)) 1089 return 0; 1090 continue; 1091 1092 default: 1093 if (!FNM_SYSCASE && ISALPHA(c) && nocase) 1094 return 1; 1095 } 1096 1097 p = Next(p-1, pend, enc); 1098 } 1099 1100 return 0; 1101} 1102 1103/* Find separator in globbing pattern. */ 1104static char * 1105find_dirsep(const char *p, const char *pend, int flags, rb_encoding *enc) 1106{ 1107 const int escape = !(flags & FNM_NOESCAPE); 1108 1109 register char c; 1110 int open = 0; 1111 1112 while ((c = *p++) != 0) { 1113 switch (c) { 1114 case '[': 1115 open = 1; 1116 continue; 1117 case ']': 1118 open = 0; 1119 continue; 1120 1121 case '/': 1122 if (!open) 1123 return (char *)p-1; 1124 continue; 1125 1126 case '\\': 1127 if (escape && !(c = *p++)) 1128 return (char *)p-1; 1129 continue; 1130 } 1131 1132 p = Next(p-1, pend, enc); 1133 } 1134 1135 return (char *)p-1; 1136} 1137 1138/* Remove escaping backslashes */ 1139static char * 1140remove_backslashes(char *p, register const char *pend, rb_encoding *enc) 1141{ 1142 char *t = p; 1143 char *s = p; 1144 1145 while (*p) { 1146 if (*p == '\\') { 1147 if (t != s) 1148 memmove(t, s, p - s); 1149 t += p - s; 1150 s = ++p; 1151 if (!*p) break; 1152 } 1153 Inc(p, pend, enc); 1154 } 1155 1156 while (*p++); 1157 1158 if (t != s) 1159 memmove(t, s, p - s); /* move '\0' too */ 1160 1161 return p; 1162} 1163 1164/* Globing pattern */ 1165enum glob_pattern_type { PLAIN, MAGICAL, RECURSIVE, MATCH_ALL, MATCH_DIR }; 1166 1167struct glob_pattern { 1168 char *str; 1169 enum glob_pattern_type type; 1170 struct glob_pattern *next; 1171}; 1172 1173static void glob_free_pattern(struct glob_pattern *list); 1174 1175static struct glob_pattern * 1176glob_make_pattern(const char *p, const char *e, int flags, rb_encoding *enc) 1177{ 1178 struct glob_pattern *list, *tmp, **tail = &list; 1179 int dirsep = 0; /* pattern is terminated with '/' */ 1180 int recursive = 0; 1181 1182 while (p < e && *p) { 1183 tmp = GLOB_ALLOC(struct glob_pattern); 1184 if (!tmp) goto error; 1185 if (p[0] == '*' && p[1] == '*' && p[2] == '/') { 1186 /* fold continuous RECURSIVEs (needed in glob_helper) */ 1187 do { p += 3; while (*p == '/') p++; } while (p[0] == '*' && p[1] == '*' && p[2] == '/'); 1188 tmp->type = RECURSIVE; 1189 tmp->str = 0; 1190 dirsep = 1; 1191 recursive = 1; 1192 } 1193 else { 1194 const char *m = find_dirsep(p, e, flags, enc); 1195 int magic = has_magic(p, m, flags, enc); 1196 char *buf; 1197 1198 if (!magic && !recursive && *m) { 1199 const char *m2; 1200 while (!has_magic(m+1, m2 = find_dirsep(m+1, e, flags, enc), flags, enc) && 1201 *m2) { 1202 m = m2; 1203 } 1204 } 1205 buf = GLOB_ALLOC_N(char, m-p+1); 1206 if (!buf) { 1207 GLOB_FREE(tmp); 1208 goto error; 1209 } 1210 memcpy(buf, p, m-p); 1211 buf[m-p] = '\0'; 1212 tmp->type = magic ? MAGICAL : PLAIN; 1213 tmp->str = buf; 1214 if (*m) { 1215 dirsep = 1; 1216 p = m + 1; 1217 } 1218 else { 1219 dirsep = 0; 1220 p = m; 1221 } 1222 } 1223 *tail = tmp; 1224 tail = &tmp->next; 1225 } 1226 1227 tmp = GLOB_ALLOC(struct glob_pattern); 1228 if (!tmp) { 1229 error: 1230 *tail = 0; 1231 glob_free_pattern(list); 1232 return 0; 1233 } 1234 tmp->type = dirsep ? MATCH_DIR : MATCH_ALL; 1235 tmp->str = 0; 1236 *tail = tmp; 1237 tmp->next = 0; 1238 1239 return list; 1240} 1241 1242static void 1243glob_free_pattern(struct glob_pattern *list) 1244{ 1245 while (list) { 1246 struct glob_pattern *tmp = list; 1247 list = list->next; 1248 if (tmp->str) 1249 GLOB_FREE(tmp->str); 1250 GLOB_FREE(tmp); 1251 } 1252} 1253 1254static char * 1255join_path(const char *path, int dirsep, const char *name, size_t namlen) 1256{ 1257 long len = strlen(path); 1258 char *buf = GLOB_ALLOC_N(char, len+namlen+(dirsep?1:0)+1); 1259 1260 if (!buf) return 0; 1261 memcpy(buf, path, len); 1262 if (dirsep) { 1263 buf[len++] = '/'; 1264 } 1265 memcpy(buf+len, name, namlen); 1266 buf[len+namlen] = '\0'; 1267 return buf; 1268} 1269 1270enum answer {UNKNOWN = -1, NO, YES}; 1271 1272#ifndef S_ISDIR 1273# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) 1274#endif 1275 1276#ifndef S_ISLNK 1277# ifndef S_IFLNK 1278# define S_ISLNK(m) (0) 1279# else 1280# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) 1281# endif 1282#endif 1283 1284struct glob_args { 1285 void (*func)(const char *, VALUE, void *); 1286 const char *path; 1287 VALUE value; 1288 rb_encoding *enc; 1289}; 1290 1291static VALUE 1292glob_func_caller(VALUE val) 1293{ 1294 struct glob_args *args = (struct glob_args *)val; 1295 1296 (*args->func)(args->path, args->value, args->enc); 1297 return Qnil; 1298} 1299 1300#define glob_call_func(func, path, arg, enc) (*(func))((path), (arg), (enc)) 1301 1302static int 1303glob_helper( 1304 const char *path, 1305 int dirsep, /* '/' should be placed before appending child entry's name to 'path'. */ 1306 enum answer exist, /* Does 'path' indicate an existing entry? */ 1307 enum answer isdir, /* Does 'path' indicate a directory or a symlink to a directory? */ 1308 struct glob_pattern **beg, 1309 struct glob_pattern **end, 1310 int flags, 1311 ruby_glob_func *func, 1312 VALUE arg, 1313 rb_encoding *enc) 1314{ 1315 struct stat st; 1316 int status = 0; 1317 struct glob_pattern **cur, **new_beg, **new_end; 1318 int plain = 0, magical = 0, recursive = 0, match_all = 0, match_dir = 0; 1319 int escape = !(flags & FNM_NOESCAPE); 1320 1321 for (cur = beg; cur < end; ++cur) { 1322 struct glob_pattern *p = *cur; 1323 if (p->type == RECURSIVE) { 1324 recursive = 1; 1325 p = p->next; 1326 } 1327 switch (p->type) { 1328 case PLAIN: 1329 plain = 1; 1330 break; 1331 case MAGICAL: 1332 magical = 1; 1333 break; 1334 case MATCH_ALL: 1335 match_all = 1; 1336 break; 1337 case MATCH_DIR: 1338 match_dir = 1; 1339 break; 1340 case RECURSIVE: 1341 rb_bug("continuous RECURSIVEs"); 1342 } 1343 } 1344 1345 if (*path) { 1346 if (match_all && exist == UNKNOWN) { 1347 if (do_lstat(path, &st, flags) == 0) { 1348 exist = YES; 1349 isdir = S_ISDIR(st.st_mode) ? YES : S_ISLNK(st.st_mode) ? UNKNOWN : NO; 1350 } 1351 else { 1352 exist = NO; 1353 isdir = NO; 1354 } 1355 } 1356 if (match_dir && isdir == UNKNOWN) { 1357 if (do_stat(path, &st, flags) == 0) { 1358 exist = YES; 1359 isdir = S_ISDIR(st.st_mode) ? YES : NO; 1360 } 1361 else { 1362 exist = NO; 1363 isdir = NO; 1364 } 1365 } 1366 if (match_all && exist == YES) { 1367 status = glob_call_func(func, path, arg, enc); 1368 if (status) return status; 1369 } 1370 if (match_dir && isdir == YES) { 1371 char *tmp = join_path(path, dirsep, "", 0); 1372 if (!tmp) return -1; 1373 status = glob_call_func(func, tmp, arg, enc); 1374 GLOB_FREE(tmp); 1375 if (status) return status; 1376 } 1377 } 1378 1379 if (exist == NO || isdir == NO) return 0; 1380 1381 if (magical || recursive) { 1382 struct dirent *dp; 1383 DIR *dirp; 1384 IF_HAVE_READDIR_R(DEFINE_STRUCT_DIRENT entry); 1385 dirp = do_opendir(*path ? path : ".", flags, enc); 1386 if (dirp == NULL) return 0; 1387 1388 while (READDIR(dirp, enc, &STRUCT_DIRENT(entry), dp)) { 1389 char *buf; 1390 enum answer new_isdir = UNKNOWN; 1391 int dotfile = 0; 1392 1393 if (recursive && dp->d_name[0] == '.') { 1394 ++dotfile; 1395 if (!dp->d_name[1]) { 1396 /* unless DOTMATCH, skip current directories not to recurse infinitely */ 1397 if (!(flags & FNM_DOTMATCH)) continue; 1398 ++dotfile; 1399 } 1400 else if (dp->d_name[1] == '.' && !dp->d_name[2]) { 1401 /* always skip parent directories not to recurse infinitely */ 1402 continue; 1403 } 1404 } 1405 1406 buf = join_path(path, dirsep, dp->d_name, NAMLEN(dp)); 1407 if (!buf) { 1408 status = -1; 1409 break; 1410 } 1411 if (recursive && dotfile < ((flags & FNM_DOTMATCH) ? 2 : 1)) { 1412 /* RECURSIVE never match dot files unless FNM_DOTMATCH is set */ 1413#ifndef _WIN32 1414 if (do_lstat(buf, &st, flags) == 0) 1415 new_isdir = S_ISDIR(st.st_mode) ? YES : S_ISLNK(st.st_mode) ? UNKNOWN : NO; 1416 else 1417 new_isdir = NO; 1418#else 1419 new_isdir = dp->d_isdir ? (!dp->d_isrep ? YES : UNKNOWN) : NO; 1420#endif 1421 } 1422 1423 new_beg = new_end = GLOB_ALLOC_N(struct glob_pattern *, (end - beg) * 2); 1424 if (!new_beg) { 1425 GLOB_FREE(buf); 1426 status = -1; 1427 break; 1428 } 1429 1430 for (cur = beg; cur < end; ++cur) { 1431 struct glob_pattern *p = *cur; 1432 if (p->type == RECURSIVE) { 1433 if (new_isdir == YES) /* not symlink but real directory */ 1434 *new_end++ = p; /* append recursive pattern */ 1435 p = p->next; /* 0 times recursion */ 1436 } 1437 if (p->type == PLAIN || p->type == MAGICAL) { 1438 if (fnmatch(p->str, enc, dp->d_name, flags) == 0) 1439 *new_end++ = p->next; 1440 } 1441 } 1442 1443 status = glob_helper(buf, 1, YES, new_isdir, new_beg, new_end, 1444 flags, func, arg, enc); 1445 GLOB_FREE(buf); 1446 GLOB_FREE(new_beg); 1447 if (status) break; 1448 } 1449 1450 closedir(dirp); 1451 } 1452 else if (plain) { 1453 struct glob_pattern **copy_beg, **copy_end, **cur2; 1454 1455 copy_beg = copy_end = GLOB_ALLOC_N(struct glob_pattern *, end - beg); 1456 if (!copy_beg) return -1; 1457 for (cur = beg; cur < end; ++cur) 1458 *copy_end++ = (*cur)->type == PLAIN ? *cur : 0; 1459 1460 for (cur = copy_beg; cur < copy_end; ++cur) { 1461 if (*cur) { 1462 char *buf; 1463 char *name; 1464 size_t len = strlen((*cur)->str) + 1; 1465 name = GLOB_ALLOC_N(char, len); 1466 if (!name) { 1467 status = -1; 1468 break; 1469 } 1470 memcpy(name, (*cur)->str, len); 1471 if (escape) 1472 len = remove_backslashes(name, name+len-1, enc) - name; 1473 1474 new_beg = new_end = GLOB_ALLOC_N(struct glob_pattern *, end - beg); 1475 if (!new_beg) { 1476 GLOB_FREE(name); 1477 status = -1; 1478 break; 1479 } 1480 *new_end++ = (*cur)->next; 1481 for (cur2 = cur + 1; cur2 < copy_end; ++cur2) { 1482 if (*cur2 && fnmatch((*cur2)->str, enc, name, flags) == 0) { 1483 *new_end++ = (*cur2)->next; 1484 *cur2 = 0; 1485 } 1486 } 1487 1488 buf = join_path(path, dirsep, name, len); 1489 GLOB_FREE(name); 1490 if (!buf) { 1491 GLOB_FREE(new_beg); 1492 status = -1; 1493 break; 1494 } 1495 status = glob_helper(buf, 1, UNKNOWN, UNKNOWN, new_beg, 1496 new_end, flags, func, arg, enc); 1497 GLOB_FREE(buf); 1498 GLOB_FREE(new_beg); 1499 if (status) break; 1500 } 1501 } 1502 1503 GLOB_FREE(copy_beg); 1504 } 1505 1506 return status; 1507} 1508 1509static int 1510ruby_glob0(const char *path, int flags, ruby_glob_func *func, VALUE arg, rb_encoding *enc) 1511{ 1512 struct glob_pattern *list; 1513 const char *root, *start; 1514 char *buf; 1515 size_t n; 1516 int status; 1517 1518 start = root = path; 1519 flags |= FNM_SYSCASE; 1520#if defined DOSISH 1521 root = rb_enc_path_skip_prefix(root, root + strlen(root), enc); 1522#endif 1523 1524 if (root && *root == '/') root++; 1525 1526 n = root - start; 1527 buf = GLOB_ALLOC_N(char, n + 1); 1528 if (!buf) return -1; 1529 MEMCPY(buf, start, char, n); 1530 buf[n] = '\0'; 1531 1532 list = glob_make_pattern(root, root + strlen(root), flags, enc); 1533 if (!list) { 1534 GLOB_FREE(buf); 1535 return -1; 1536 } 1537 status = glob_helper(buf, 0, UNKNOWN, UNKNOWN, &list, &list + 1, flags, func, arg, enc); 1538 glob_free_pattern(list); 1539 GLOB_FREE(buf); 1540 1541 return status; 1542} 1543 1544int 1545ruby_glob(const char *path, int flags, ruby_glob_func *func, VALUE arg) 1546{ 1547 return ruby_glob0(path, flags & ~GLOB_VERBOSE, func, arg, 1548 rb_ascii8bit_encoding()); 1549} 1550 1551static int 1552rb_glob_caller(const char *path, VALUE a, void *enc) 1553{ 1554 int status; 1555 struct glob_args *args = (struct glob_args *)a; 1556 1557 args->path = path; 1558 rb_protect(glob_func_caller, a, &status); 1559 return status; 1560} 1561 1562static int 1563rb_glob2(const char *path, int flags, 1564 void (*func)(const char *, VALUE, void *), VALUE arg, 1565 rb_encoding* enc) 1566{ 1567 struct glob_args args; 1568 1569 args.func = func; 1570 args.value = arg; 1571 args.enc = enc; 1572 1573 if (flags & FNM_SYSCASE) { 1574 rb_warning("Dir.glob() ignores File::FNM_CASEFOLD"); 1575 } 1576 1577 return ruby_glob0(path, flags | GLOB_VERBOSE, rb_glob_caller, (VALUE)&args, 1578 enc); 1579} 1580 1581void 1582rb_glob(const char *path, void (*func)(const char *, VALUE, void *), VALUE arg) 1583{ 1584 int status = rb_glob2(path, 0, func, arg, rb_ascii8bit_encoding()); 1585 if (status) GLOB_JUMP_TAG(status); 1586} 1587 1588static void 1589push_pattern(const char *path, VALUE ary, void *enc) 1590{ 1591 rb_ary_push(ary, rb_external_str_new_with_enc(path, strlen(path), enc)); 1592} 1593 1594static int 1595ruby_brace_expand(const char *str, int flags, ruby_glob_func *func, VALUE arg, 1596 rb_encoding *enc) 1597{ 1598 const int escape = !(flags & FNM_NOESCAPE); 1599 const char *p = str; 1600 const char *pend = p + strlen(p); 1601 const char *s = p; 1602 const char *lbrace = 0, *rbrace = 0; 1603 int nest = 0, status = 0; 1604 1605 while (*p) { 1606 if (*p == '{' && nest++ == 0) { 1607 lbrace = p; 1608 } 1609 if (*p == '}' && --nest <= 0) { 1610 rbrace = p; 1611 break; 1612 } 1613 if (*p == '\\' && escape) { 1614 if (!*++p) break; 1615 } 1616 Inc(p, pend, enc); 1617 } 1618 1619 if (lbrace && rbrace) { 1620 size_t len = strlen(s) + 1; 1621 char *buf = GLOB_ALLOC_N(char, len); 1622 long shift; 1623 1624 if (!buf) return -1; 1625 memcpy(buf, s, lbrace-s); 1626 shift = (lbrace-s); 1627 p = lbrace; 1628 while (p < rbrace) { 1629 const char *t = ++p; 1630 nest = 0; 1631 while (p < rbrace && !(*p == ',' && nest == 0)) { 1632 if (*p == '{') nest++; 1633 if (*p == '}') nest--; 1634 if (*p == '\\' && escape) { 1635 if (++p == rbrace) break; 1636 } 1637 Inc(p, pend, enc); 1638 } 1639 memcpy(buf+shift, t, p-t); 1640 strlcpy(buf+shift+(p-t), rbrace+1, len-(shift+(p-t))); 1641 status = ruby_brace_expand(buf, flags, func, arg, enc); 1642 if (status) break; 1643 } 1644 GLOB_FREE(buf); 1645 } 1646 else if (!lbrace && !rbrace) { 1647 status = (*func)(s, arg, enc); 1648 } 1649 1650 return status; 1651} 1652 1653struct brace_args { 1654 ruby_glob_func *func; 1655 VALUE value; 1656 int flags; 1657}; 1658 1659static int 1660glob_brace(const char *path, VALUE val, void *enc) 1661{ 1662 struct brace_args *arg = (struct brace_args *)val; 1663 1664 return ruby_glob0(path, arg->flags, arg->func, arg->value, enc); 1665} 1666 1667static int 1668ruby_brace_glob0(const char *str, int flags, ruby_glob_func *func, VALUE arg, 1669 rb_encoding* enc) 1670{ 1671 struct brace_args args; 1672 1673 args.func = func; 1674 args.value = arg; 1675 args.flags = flags; 1676 return ruby_brace_expand(str, flags, glob_brace, (VALUE)&args, enc); 1677} 1678 1679int 1680ruby_brace_glob(const char *str, int flags, ruby_glob_func *func, VALUE arg) 1681{ 1682 return ruby_brace_glob0(str, flags & ~GLOB_VERBOSE, func, arg, 1683 rb_ascii8bit_encoding()); 1684} 1685 1686int 1687ruby_brace_glob_with_enc(const char *str, int flags, ruby_glob_func *func, VALUE arg, rb_encoding *enc) 1688{ 1689 return ruby_brace_glob0(str, flags & ~GLOB_VERBOSE, func, arg, enc); 1690} 1691 1692static int 1693push_glob(VALUE ary, VALUE str, int flags) 1694{ 1695 struct glob_args args; 1696 rb_encoding *enc = rb_enc_get(str); 1697 1698 if (enc == rb_usascii_encoding()) enc = rb_filesystem_encoding(); 1699 args.func = push_pattern; 1700 args.value = ary; 1701 args.enc = enc; 1702 1703 RB_GC_GUARD(str); 1704 return ruby_brace_glob0(RSTRING_PTR(str), flags | GLOB_VERBOSE, 1705 rb_glob_caller, (VALUE)&args, enc); 1706} 1707 1708static VALUE 1709rb_push_glob(VALUE str, int flags) /* '\0' is delimiter */ 1710{ 1711 long offset = 0; 1712 VALUE ary; 1713 1714 GlobPathValue(str, TRUE); 1715 ary = rb_ary_new(); 1716 1717 while (offset < RSTRING_LEN(str)) { 1718 char *p, *pend; 1719 int status; 1720 p = RSTRING_PTR(str) + offset; 1721 status = push_glob(ary, rb_enc_str_new(p, strlen(p), rb_enc_get(str)), 1722 flags); 1723 if (status) GLOB_JUMP_TAG(status); 1724 if (offset >= RSTRING_LEN(str)) break; 1725 p += strlen(p) + 1; 1726 pend = RSTRING_PTR(str) + RSTRING_LEN(str); 1727 while (p < pend && !*p) 1728 p++; 1729 offset = p - RSTRING_PTR(str); 1730 } 1731 1732 return ary; 1733} 1734 1735static VALUE 1736dir_globs(long argc, VALUE *argv, int flags) 1737{ 1738 VALUE ary = rb_ary_new(); 1739 long i; 1740 1741 for (i = 0; i < argc; ++i) { 1742 int status; 1743 VALUE str = argv[i]; 1744 GlobPathValue(str, TRUE); 1745 status = push_glob(ary, str, flags); 1746 if (status) GLOB_JUMP_TAG(status); 1747 } 1748 1749 return ary; 1750} 1751 1752/* 1753 * call-seq: 1754 * Dir[ array ] -> array 1755 * Dir[ string [, string ...] ] -> array 1756 * 1757 * Equivalent to calling 1758 * <code>Dir.glob(</code><i>array,</i><code>0)</code> and 1759 * <code>Dir.glob([</code><i>string,...</i><code>],0)</code>. 1760 * 1761 */ 1762static VALUE 1763dir_s_aref(int argc, VALUE *argv, VALUE obj) 1764{ 1765 if (argc == 1) { 1766 return rb_push_glob(argv[0], 0); 1767 } 1768 return dir_globs(argc, argv, 0); 1769} 1770 1771/* 1772 * call-seq: 1773 * Dir.glob( pattern, [flags] ) -> array 1774 * Dir.glob( pattern, [flags] ) {| filename | block } -> nil 1775 * 1776 * Returns the filenames found by expanding <i>pattern</i> which is 1777 * an +Array+ of the patterns or the pattern +String+, either as an 1778 * <i>array</i> or as parameters to the block. Note that this pattern 1779 * is not a regexp (it's closer to a shell glob). See 1780 * <code>File::fnmatch</code> for the meaning of the <i>flags</i> 1781 * parameter. Note that case sensitivity depends on your system (so 1782 * <code>File::FNM_CASEFOLD</code> is ignored), as does the order 1783 * in which the results are returned. 1784 * 1785 * <code>*</code>:: Matches any file. Can be restricted by 1786 * other values in the glob. <code>*</code> 1787 * will match all files; <code>c*</code> will 1788 * match all files beginning with 1789 * <code>c</code>; <code>*c</code> will match 1790 * all files ending with <code>c</code>; and 1791 * <code>\*c\*</code> will match all files that 1792 * have <code>c</code> in them (including at 1793 * the beginning or end). Equivalent to 1794 * <code>/ .* /x</code> in regexp. Note, this 1795 * will not match Unix-like hidden files (dotfiles). 1796 * In order to include those in the match results, 1797 * you must use something like <code>"{*,.*}"</code>. 1798 * <code>**</code>:: Matches directories recursively. 1799 * <code>?</code>:: Matches any one character. Equivalent to 1800 * <code>/.{1}/</code> in regexp. 1801 * <code>[set]</code>:: Matches any one character in +set+. 1802 * Behaves exactly like character sets in 1803 * Regexp, including set negation 1804 * (<code>[^a-z]</code>). 1805 * <code>{p,q}</code>:: Matches either literal <code>p</code> or 1806 * literal <code>q</code>. Matching literals 1807 * may be more than one character in length. 1808 * More than two literals may be specified. 1809 * Equivalent to pattern alternation in 1810 * regexp. 1811 * <code> \\ </code>:: Escapes the next metacharacter. 1812 * Note that this means you cannot use backslash 1813 * in windows as part of a glob, 1814 * i.e. <code>Dir["c:\\foo*"]</code> will not work, 1815 * use <code>Dir["c:/foo*"]</code> instead. 1816 * 1817 * Dir["config.?"] #=> ["config.h"] 1818 * Dir.glob("config.?") #=> ["config.h"] 1819 * Dir.glob("*.[a-z][a-z]") #=> ["main.rb"] 1820 * Dir.glob("*.[^r]*") #=> ["config.h"] 1821 * Dir.glob("*.{rb,h}") #=> ["main.rb", "config.h"] 1822 * Dir.glob("*") #=> ["config.h", "main.rb"] 1823 * Dir.glob("*", File::FNM_DOTMATCH) #=> [".", "..", "config.h", "main.rb"] 1824 * 1825 * rbfiles = File.join("**", "*.rb") 1826 * Dir.glob(rbfiles) #=> ["main.rb", 1827 * # "lib/song.rb", 1828 * # "lib/song/karaoke.rb"] 1829 * libdirs = File.join("**", "lib") 1830 * Dir.glob(libdirs) #=> ["lib"] 1831 * 1832 * librbfiles = File.join("**", "lib", "**", "*.rb") 1833 * Dir.glob(librbfiles) #=> ["lib/song.rb", 1834 * # "lib/song/karaoke.rb"] 1835 * 1836 * librbfiles = File.join("**", "lib", "*.rb") 1837 * Dir.glob(librbfiles) #=> ["lib/song.rb"] 1838 */ 1839static VALUE 1840dir_s_glob(int argc, VALUE *argv, VALUE obj) 1841{ 1842 VALUE str, rflags, ary; 1843 int flags; 1844 1845 if (rb_scan_args(argc, argv, "11", &str, &rflags) == 2) 1846 flags = NUM2INT(rflags); 1847 else 1848 flags = 0; 1849 1850 ary = rb_check_array_type(str); 1851 if (NIL_P(ary)) { 1852 ary = rb_push_glob(str, flags); 1853 } 1854 else { 1855 volatile VALUE v = ary; 1856 ary = dir_globs(RARRAY_LEN(v), RARRAY_PTR(v), flags); 1857 } 1858 1859 if (rb_block_given_p()) { 1860 rb_ary_each(ary); 1861 return Qnil; 1862 } 1863 return ary; 1864} 1865 1866static VALUE 1867dir_open_dir(int argc, VALUE *argv) 1868{ 1869 VALUE dir = rb_funcall2(rb_cDir, rb_intern("open"), argc, argv); 1870 1871 rb_check_typeddata(dir, &dir_data_type); 1872 return dir; 1873} 1874 1875 1876/* 1877 * call-seq: 1878 * Dir.foreach( dirname ) {| filename | block } -> nil 1879 * Dir.foreach( dirname ) -> an_enumerator 1880 * 1881 * Calls the block once for each entry in the named directory, passing 1882 * the filename of each entry as a parameter to the block. 1883 * 1884 * If no block is given, an enumerator is returned instead. 1885 * 1886 * Dir.foreach("testdir") {|x| puts "Got #{x}" } 1887 * 1888 * <em>produces:</em> 1889 * 1890 * Got . 1891 * Got .. 1892 * Got config.h 1893 * Got main.rb 1894 * 1895 */ 1896static VALUE 1897dir_foreach(int argc, VALUE *argv, VALUE io) 1898{ 1899 VALUE dir; 1900 1901 RETURN_ENUMERATOR(io, argc, argv); 1902 dir = dir_open_dir(argc, argv); 1903 rb_ensure(dir_each, dir, dir_close, dir); 1904 return Qnil; 1905} 1906 1907/* 1908 * call-seq: 1909 * Dir.entries( dirname ) -> array 1910 * 1911 * Returns an array containing all of the filenames in the given 1912 * directory. Will raise a <code>SystemCallError</code> if the named 1913 * directory doesn't exist. 1914 * 1915 * Dir.entries("testdir") #=> [".", "..", "config.h", "main.rb"] 1916 * 1917 */ 1918static VALUE 1919dir_entries(int argc, VALUE *argv, VALUE io) 1920{ 1921 VALUE dir; 1922 1923 dir = dir_open_dir(argc, argv); 1924 return rb_ensure(rb_Array, dir, dir_close, dir); 1925} 1926 1927static int 1928fnmatch_brace(const char *pattern, VALUE val, void *enc) 1929{ 1930 struct brace_args *arg = (struct brace_args *)val; 1931 VALUE path = arg->value; 1932 rb_encoding *enc_pattern = enc; 1933 rb_encoding *enc_path = rb_enc_get(path); 1934 1935 if (enc_pattern != enc_path) { 1936 if (!rb_enc_asciicompat(enc_pattern)) 1937 return FNM_NOMATCH; 1938 if (!rb_enc_asciicompat(enc_path)) 1939 return FNM_NOMATCH; 1940 if (!rb_enc_str_asciionly_p(path)) { 1941 int cr = ENC_CODERANGE_7BIT; 1942 long len = strlen(pattern); 1943 if (rb_str_coderange_scan_restartable(pattern, pattern + len, 1944 enc_pattern, &cr) != len) 1945 return FNM_NOMATCH; 1946 if (cr != ENC_CODERANGE_7BIT) 1947 return FNM_NOMATCH; 1948 } 1949 } 1950 return (fnmatch(pattern, enc, RSTRING_PTR(path), arg->flags) == 0); 1951} 1952 1953/* 1954 * call-seq: 1955 * File.fnmatch( pattern, path, [flags] ) -> (true or false) 1956 * File.fnmatch?( pattern, path, [flags] ) -> (true or false) 1957 * 1958 * Returns true if <i>path</i> matches against <i>pattern</i> The 1959 * pattern is not a regular expression; instead it follows rules 1960 * similar to shell filename globbing. It may contain the following 1961 * metacharacters: 1962 * 1963 * <code>*</code>:: Matches any file. Can be restricted by 1964 * other values in the glob. <code>*</code> 1965 * will match all files; <code>c*</code> will 1966 * match all files beginning with 1967 * <code>c</code>; <code>*c</code> will match 1968 * all files ending with <code>c</code>; and 1969 * <code>\*c*</code> will match all files that 1970 * have <code>c</code> in them (including at 1971 * the beginning or end). Equivalent to 1972 * <code>/ .* /x</code> in regexp. 1973 * <code>**</code>:: Matches directories recursively or files 1974 * expansively. 1975 * <code>?</code>:: Matches any one character. Equivalent to 1976 * <code>/.{1}/</code> in regexp. 1977 * <code>[set]</code>:: Matches any one character in +set+. 1978 * Behaves exactly like character sets in 1979 * Regexp, including set negation 1980 * (<code>[^a-z]</code>). 1981 * <code> \ </code>:: Escapes the next metacharacter. 1982 * 1983 * <i>flags</i> is a bitwise OR of the <code>FNM_xxx</code> 1984 * parameters. The same glob pattern and flags are used by 1985 * <code>Dir::glob</code>. 1986 * 1987 * File.fnmatch('cat', 'cat') #=> true # match entire string 1988 * File.fnmatch('cat', 'category') #=> false # only match partial string 1989 * File.fnmatch('c{at,ub}s', 'cats') #=> false # { } isn't supported 1990 * 1991 * File.fnmatch('c?t', 'cat') #=> true # '?' match only 1 character 1992 * File.fnmatch('c??t', 'cat') #=> false # ditto 1993 * File.fnmatch('c*', 'cats') #=> true # '*' match 0 or more characters 1994 * File.fnmatch('c*t', 'c/a/b/t') #=> true # ditto 1995 * File.fnmatch('ca[a-z]', 'cat') #=> true # inclusive bracket expression 1996 * File.fnmatch('ca[^t]', 'cat') #=> false # exclusive bracket expression ('^' or '!') 1997 * 1998 * File.fnmatch('cat', 'CAT') #=> false # case sensitive 1999 * File.fnmatch('cat', 'CAT', File::FNM_CASEFOLD) #=> true # case insensitive 2000 * 2001 * File.fnmatch('?', '/', File::FNM_PATHNAME) #=> false # wildcard doesn't match '/' on FNM_PATHNAME 2002 * File.fnmatch('*', '/', File::FNM_PATHNAME) #=> false # ditto 2003 * File.fnmatch('[/]', '/', File::FNM_PATHNAME) #=> false # ditto 2004 * 2005 * File.fnmatch('\?', '?') #=> true # escaped wildcard becomes ordinary 2006 * File.fnmatch('\a', 'a') #=> true # escaped ordinary remains ordinary 2007 * File.fnmatch('\a', '\a', File::FNM_NOESCAPE) #=> true # FNM_NOESCAPE makes '\' ordinary 2008 * File.fnmatch('[\?]', '?') #=> true # can escape inside bracket expression 2009 * 2010 * File.fnmatch('*', '.profile') #=> false # wildcard doesn't match leading 2011 * File.fnmatch('*', '.profile', File::FNM_DOTMATCH) #=> true # period by default. 2012 * File.fnmatch('.*', '.profile') #=> true 2013 * 2014 * rbfiles = '**' '/' '*.rb' # you don't have to do like this. just write in single string. 2015 * File.fnmatch(rbfiles, 'main.rb') #=> false 2016 * File.fnmatch(rbfiles, './main.rb') #=> false 2017 * File.fnmatch(rbfiles, 'lib/song.rb') #=> true 2018 * File.fnmatch('**.rb', 'main.rb') #=> true 2019 * File.fnmatch('**.rb', './main.rb') #=> false 2020 * File.fnmatch('**.rb', 'lib/song.rb') #=> true 2021 * File.fnmatch('*', 'dave/.profile') #=> true 2022 * 2023 * pattern = '*' '/' '*' 2024 * File.fnmatch(pattern, 'dave/.profile', File::FNM_PATHNAME) #=> false 2025 * File.fnmatch(pattern, 'dave/.profile', File::FNM_PATHNAME | File::FNM_DOTMATCH) #=> true 2026 * 2027 * pattern = '**' '/' 'foo' 2028 * File.fnmatch(pattern, 'a/b/c/foo', File::FNM_PATHNAME) #=> true 2029 * File.fnmatch(pattern, '/a/b/c/foo', File::FNM_PATHNAME) #=> true 2030 * File.fnmatch(pattern, 'c:/a/b/c/foo', File::FNM_PATHNAME) #=> true 2031 * File.fnmatch(pattern, 'a/.b/c/foo', File::FNM_PATHNAME) #=> false 2032 * File.fnmatch(pattern, 'a/.b/c/foo', File::FNM_PATHNAME | File::FNM_DOTMATCH) #=> true 2033 */ 2034static VALUE 2035file_s_fnmatch(int argc, VALUE *argv, VALUE obj) 2036{ 2037 VALUE pattern, path; 2038 VALUE rflags; 2039 int flags; 2040 2041 if (rb_scan_args(argc, argv, "21", &pattern, &path, &rflags) == 3) 2042 flags = NUM2INT(rflags); 2043 else 2044 flags = 0; 2045 2046 StringValue(pattern); 2047 FilePathStringValue(path); 2048 2049 if (flags & FNM_EXTGLOB) { 2050 struct brace_args args; 2051 2052 args.value = path; 2053 args.flags = flags; 2054 if (ruby_brace_expand(RSTRING_PTR(pattern), flags, fnmatch_brace, 2055 (VALUE)&args, rb_enc_get(pattern)) > 0) 2056 return Qtrue; 2057 } 2058 else { 2059 rb_encoding *enc = rb_enc_compatible(pattern, path); 2060 if (!enc) return Qfalse; 2061 if (fnmatch(RSTRING_PTR(pattern), enc, RSTRING_PTR(path), flags) == 0) 2062 return Qtrue; 2063 } 2064 RB_GC_GUARD(pattern); 2065 2066 return Qfalse; 2067} 2068 2069/* 2070 * call-seq: 2071 * Dir.home() -> "/home/me" 2072 * Dir.home("root") -> "/root" 2073 * 2074 * Returns the home directory of the current user or the named user 2075 * if given. 2076 */ 2077static VALUE 2078dir_s_home(int argc, VALUE *argv, VALUE obj) 2079{ 2080 VALUE user; 2081 const char *u = 0; 2082 2083 rb_scan_args(argc, argv, "01", &user); 2084 if (!NIL_P(user)) { 2085 SafeStringValue(user); 2086 u = StringValueCStr(user); 2087 } 2088 return rb_home_dir(u, rb_str_new(0, 0)); 2089} 2090 2091#if 0 2092/* 2093 * call-seq: 2094 * Dir.exist?(file_name) -> true or false 2095 * Dir.exists?(file_name) -> true or false 2096 * 2097 * Returns <code>true</code> if the named file is a directory, 2098 * <code>false</code> otherwise. 2099 * 2100 */ 2101VALUE 2102rb_file_directory_p() 2103{ 2104} 2105#endif 2106 2107/* 2108 * Objects of class <code>Dir</code> are directory streams representing 2109 * directories in the underlying file system. They provide a variety of 2110 * ways to list directories and their contents. See also 2111 * <code>File</code>. 2112 * 2113 * The directory used in these examples contains the two regular files 2114 * (<code>config.h</code> and <code>main.rb</code>), the parent 2115 * directory (<code>..</code>), and the directory itself 2116 * (<code>.</code>). 2117 */ 2118void 2119Init_Dir(void) 2120{ 2121 rb_cDir = rb_define_class("Dir", rb_cObject); 2122 2123 rb_include_module(rb_cDir, rb_mEnumerable); 2124 2125 rb_define_alloc_func(rb_cDir, dir_s_alloc); 2126 rb_define_singleton_method(rb_cDir, "open", dir_s_open, -1); 2127 rb_define_singleton_method(rb_cDir, "foreach", dir_foreach, -1); 2128 rb_define_singleton_method(rb_cDir, "entries", dir_entries, -1); 2129 2130 rb_define_method(rb_cDir,"initialize", dir_initialize, -1); 2131 rb_define_method(rb_cDir,"path", dir_path, 0); 2132 rb_define_method(rb_cDir,"to_path", dir_path, 0); 2133 rb_define_method(rb_cDir,"inspect", dir_inspect, 0); 2134 rb_define_method(rb_cDir,"read", dir_read, 0); 2135 rb_define_method(rb_cDir,"each", dir_each, 0); 2136 rb_define_method(rb_cDir,"rewind", dir_rewind, 0); 2137 rb_define_method(rb_cDir,"tell", dir_tell, 0); 2138 rb_define_method(rb_cDir,"seek", dir_seek, 1); 2139 rb_define_method(rb_cDir,"pos", dir_tell, 0); 2140 rb_define_method(rb_cDir,"pos=", dir_set_pos, 1); 2141 rb_define_method(rb_cDir,"close", dir_close, 0); 2142 2143 rb_define_singleton_method(rb_cDir,"chdir", dir_s_chdir, -1); 2144 rb_define_singleton_method(rb_cDir,"getwd", dir_s_getwd, 0); 2145 rb_define_singleton_method(rb_cDir,"pwd", dir_s_getwd, 0); 2146 rb_define_singleton_method(rb_cDir,"chroot", dir_s_chroot, 1); 2147 rb_define_singleton_method(rb_cDir,"mkdir", dir_s_mkdir, -1); 2148 rb_define_singleton_method(rb_cDir,"rmdir", dir_s_rmdir, 1); 2149 rb_define_singleton_method(rb_cDir,"delete", dir_s_rmdir, 1); 2150 rb_define_singleton_method(rb_cDir,"unlink", dir_s_rmdir, 1); 2151 rb_define_singleton_method(rb_cDir,"home", dir_s_home, -1); 2152 2153 rb_define_singleton_method(rb_cDir,"glob", dir_s_glob, -1); 2154 rb_define_singleton_method(rb_cDir,"[]", dir_s_aref, -1); 2155 rb_define_singleton_method(rb_cDir,"exist?", rb_file_directory_p, 1); 2156 rb_define_singleton_method(rb_cDir,"exists?", rb_file_directory_p, 1); 2157 2158 rb_define_singleton_method(rb_cFile,"fnmatch", file_s_fnmatch, -1); 2159 rb_define_singleton_method(rb_cFile,"fnmatch?", file_s_fnmatch, -1); 2160 2161 rb_file_const("FNM_NOESCAPE", INT2FIX(FNM_NOESCAPE)); 2162 rb_file_const("FNM_PATHNAME", INT2FIX(FNM_PATHNAME)); 2163 rb_file_const("FNM_DOTMATCH", INT2FIX(FNM_DOTMATCH)); 2164 rb_file_const("FNM_CASEFOLD", INT2FIX(FNM_CASEFOLD)); 2165 rb_file_const("FNM_EXTGLOB", INT2FIX(FNM_EXTGLOB)); 2166 rb_file_const("FNM_SYSCASE", INT2FIX(FNM_SYSCASE)); 2167} 2168