00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
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 #
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
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,
00104 const char *pend,
00105 const char *s,
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
00171
00172
00173
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,
00182 const char **scur,
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) != '.')
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
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:
00261 if (ptmp && stmp) {
00262 p = ptmp;
00263 Inc(stmp, send, enc);
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
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 \
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
00383
00384
00385
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
00436
00437
00438
00439
00440
00441
00442
00443
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
00482
00483
00484
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
00505
00506
00507
00508
00509
00510
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)
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
00570
00571
00572
00573
00574
00575
00576
00577
00578
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) {
00593 return Qnil;
00594 }
00595 else {
00596 rb_sys_fail(0);
00597 }
00598 return Qnil;
00599 }
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
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
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
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
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
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
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
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
00718
00719
00720
00721
00722
00723
00724
00725
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
00742
00743
00744
00745
00746
00747
00748
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 path = rb_str_encode_ospath(path);
00766 if (chdir(RSTRING_PTR(path)) < 0)
00767 rb_sys_fail_path(path);
00768 }
00769
00770 static int chdir_blocking = 0;
00771 static VALUE chdir_thread = Qnil;
00772
00773 struct chdir_data {
00774 VALUE old_path, new_path;
00775 int done;
00776 };
00777
00778 static VALUE
00779 chdir_yield(struct chdir_data *args)
00780 {
00781 dir_chdir(args->new_path);
00782 args->done = TRUE;
00783 chdir_blocking++;
00784 if (chdir_thread == Qnil)
00785 chdir_thread = rb_thread_current();
00786 return rb_yield(args->new_path);
00787 }
00788
00789 static VALUE
00790 chdir_restore(struct chdir_data *args)
00791 {
00792 if (args->done) {
00793 chdir_blocking--;
00794 if (chdir_blocking == 0)
00795 chdir_thread = Qnil;
00796 dir_chdir(args->old_path);
00797 }
00798 return Qnil;
00799 }
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840 static VALUE
00841 dir_s_chdir(int argc, VALUE *argv, VALUE obj)
00842 {
00843 VALUE path = Qnil;
00844
00845 rb_secure(2);
00846 if (rb_scan_args(argc, argv, "01", &path) == 1) {
00847 FilePathValue(path);
00848 }
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 char *cwd = my_getcwd();
00866
00867 args.old_path = rb_tainted_str_new2(cwd); xfree(cwd);
00868 args.new_path = path;
00869 args.done = FALSE;
00870 return rb_ensure(chdir_yield, (VALUE)&args, chdir_restore, (VALUE)&args);
00871 }
00872 dir_chdir(path);
00873
00874 return INT2FIX(0);
00875 }
00876
00877 VALUE
00878 rb_dir_getwd(void)
00879 {
00880 char *path;
00881 VALUE cwd;
00882
00883 rb_secure(4);
00884 path = my_getcwd();
00885 cwd = rb_tainted_str_new2(path);
00886 rb_enc_associate(cwd, rb_filesystem_encoding());
00887
00888 xfree(path);
00889 return cwd;
00890 }
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903 static VALUE
00904 dir_s_getwd(VALUE dir)
00905 {
00906 return rb_dir_getwd();
00907 }
00908
00909 static void
00910 check_dirname(volatile VALUE *dir)
00911 {
00912 char *path, *pend;
00913
00914 rb_secure(2);
00915 FilePathValue(*dir);
00916 path = RSTRING_PTR(*dir);
00917 if (path && *(pend = rb_path_end(rb_path_skip_prefix(path)))) {
00918 *dir = rb_str_new(path, pend - path);
00919 }
00920 }
00921
00922 #if defined(HAVE_CHROOT)
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932 static VALUE
00933 dir_s_chroot(VALUE dir, VALUE path)
00934 {
00935 check_dirname(&path);
00936
00937 path = rb_str_encode_ospath(path);
00938 if (chroot(RSTRING_PTR(path)) == -1)
00939 rb_sys_fail_path(path);
00940
00941 return INT2FIX(0);
00942 }
00943 #else
00944 #define dir_s_chroot rb_f_notimplement
00945 #endif
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962 static VALUE
00963 dir_s_mkdir(int argc, VALUE *argv, VALUE obj)
00964 {
00965 VALUE path, vmode;
00966 int mode;
00967
00968 if (rb_scan_args(argc, argv, "11", &path, &vmode) == 2) {
00969 mode = NUM2INT(vmode);
00970 }
00971 else {
00972 mode = 0777;
00973 }
00974
00975 check_dirname(&path);
00976 path = rb_str_encode_ospath(path);
00977 if (mkdir(RSTRING_PTR(path), mode) == -1)
00978 rb_sys_fail_path(path);
00979
00980 return INT2FIX(0);
00981 }
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992 static VALUE
00993 dir_s_rmdir(VALUE obj, VALUE dir)
00994 {
00995 check_dirname(&dir);
00996 dir = rb_str_encode_ospath(dir);
00997 if (rmdir(RSTRING_PTR(dir)) < 0)
00998 rb_sys_fail_path(dir);
00999
01000 return INT2FIX(0);
01001 }
01002
01003 static VALUE
01004 sys_warning_1(VALUE mesg)
01005 {
01006 rb_sys_warning("%s:%s", strerror(errno), (const char *)mesg);
01007 return Qnil;
01008 }
01009
01010 #define GLOB_VERBOSE (1U << (sizeof(int) * CHAR_BIT - 1))
01011 #define sys_warning(val) \
01012 (void)((flags & GLOB_VERBOSE) && rb_protect(sys_warning_1, (VALUE)(val), 0))
01013
01014 #define GLOB_ALLOC(type) ((type *)malloc(sizeof(type)))
01015 #define GLOB_ALLOC_N(type, n) ((type *)malloc(sizeof(type) * (n)))
01016 #define GLOB_FREE(ptr) free(ptr)
01017 #define GLOB_JUMP_TAG(status) (((status) == -1) ? rb_memerror() : rb_jump_tag(status))
01018
01019
01020
01021
01022
01023 #define to_be_ignored(e) ((e) == ENOENT || (e) == ENOTDIR)
01024
01025
01026 static int
01027 do_stat(const char *path, struct stat *pst, int flags)
01028
01029 {
01030 int ret = stat(path, pst);
01031 if (ret < 0 && !to_be_ignored(errno))
01032 sys_warning(path);
01033
01034 return ret;
01035 }
01036
01037 static int
01038 do_lstat(const char *path, struct stat *pst, int flags)
01039 {
01040 int ret = lstat(path, pst);
01041 if (ret < 0 && !to_be_ignored(errno))
01042 sys_warning(path);
01043
01044 return ret;
01045 }
01046
01047 static DIR *
01048 do_opendir(const char *path, int flags, rb_encoding *enc)
01049 {
01050 DIR *dirp;
01051 #ifdef _WIN32
01052 volatile VALUE tmp;
01053 if (enc != rb_usascii_encoding() &&
01054 enc != rb_ascii8bit_encoding() &&
01055 enc != rb_utf8_encoding()) {
01056 tmp = rb_enc_str_new(path, strlen(path), enc);
01057 tmp = rb_str_encode_ospath(tmp);
01058 path = RSTRING_PTR(tmp);
01059 }
01060 #endif
01061 dirp = opendir(path);
01062 if (dirp == NULL && !to_be_ignored(errno))
01063 sys_warning(path);
01064
01065 return dirp;
01066 }
01067
01068
01069 static int
01070 has_magic(const char *p, const char *pend, int flags, rb_encoding *enc)
01071 {
01072 const int escape = !(flags & FNM_NOESCAPE);
01073 const int nocase = flags & FNM_CASEFOLD;
01074
01075 register char c;
01076
01077 while (p < pend && (c = *p++) != 0) {
01078 switch (c) {
01079 case '*':
01080 case '?':
01081 case '[':
01082 return 1;
01083
01084 case '\\':
01085 if (escape && !(c = *p++))
01086 return 0;
01087 continue;
01088
01089 default:
01090 if (!FNM_SYSCASE && ISALPHA(c) && nocase)
01091 return 1;
01092 }
01093
01094 p = Next(p-1, pend, enc);
01095 }
01096
01097 return 0;
01098 }
01099
01100
01101 static char *
01102 find_dirsep(const char *p, const char *pend, int flags, rb_encoding *enc)
01103 {
01104 const int escape = !(flags & FNM_NOESCAPE);
01105
01106 register char c;
01107 int open = 0;
01108
01109 while ((c = *p++) != 0) {
01110 switch (c) {
01111 case '[':
01112 open = 1;
01113 continue;
01114 case ']':
01115 open = 0;
01116 continue;
01117
01118 case '/':
01119 if (!open)
01120 return (char *)p-1;
01121 continue;
01122
01123 case '\\':
01124 if (escape && !(c = *p++))
01125 return (char *)p-1;
01126 continue;
01127 }
01128
01129 p = Next(p-1, pend, enc);
01130 }
01131
01132 return (char *)p-1;
01133 }
01134
01135
01136 static void
01137 remove_backslashes(char *p, rb_encoding *enc)
01138 {
01139 register const char *pend = p + strlen(p);
01140 char *t = p;
01141 char *s = p;
01142
01143 while (*p) {
01144 if (*p == '\\') {
01145 if (t != s)
01146 memmove(t, s, p - s);
01147 t += p - s;
01148 s = ++p;
01149 if (!*p) break;
01150 }
01151 Inc(p, pend, enc);
01152 }
01153
01154 while (*p++);
01155
01156 if (t != s)
01157 memmove(t, s, p - s);
01158 }
01159
01160
01161 enum glob_pattern_type { PLAIN, MAGICAL, RECURSIVE, MATCH_ALL, MATCH_DIR };
01162
01163 struct glob_pattern {
01164 char *str;
01165 enum glob_pattern_type type;
01166 struct glob_pattern *next;
01167 };
01168
01169 static void glob_free_pattern(struct glob_pattern *list);
01170
01171 static struct glob_pattern *
01172 glob_make_pattern(const char *p, const char *e, int flags, rb_encoding *enc)
01173 {
01174 struct glob_pattern *list, *tmp, **tail = &list;
01175 int dirsep = 0;
01176
01177 while (p < e && *p) {
01178 tmp = GLOB_ALLOC(struct glob_pattern);
01179 if (!tmp) goto error;
01180 if (p[0] == '*' && p[1] == '*' && p[2] == '/') {
01181
01182 do { p += 3; while (*p == '/') p++; } while (p[0] == '*' && p[1] == '*' && p[2] == '/');
01183 tmp->type = RECURSIVE;
01184 tmp->str = 0;
01185 dirsep = 1;
01186 }
01187 else {
01188 const char *m = find_dirsep(p, e, flags, enc);
01189 int magic = has_magic(p, m, flags, enc);
01190 char *buf;
01191
01192 if (!magic && *m) {
01193 const char *m2;
01194 while (!has_magic(m+1, m2 = find_dirsep(m+1, e, flags, enc), flags, enc) &&
01195 *m2) {
01196 m = m2;
01197 }
01198 }
01199 buf = GLOB_ALLOC_N(char, m-p+1);
01200 if (!buf) {
01201 GLOB_FREE(tmp);
01202 goto error;
01203 }
01204 memcpy(buf, p, m-p);
01205 buf[m-p] = '\0';
01206 tmp->type = magic ? MAGICAL : PLAIN;
01207 tmp->str = buf;
01208 if (*m) {
01209 dirsep = 1;
01210 p = m + 1;
01211 }
01212 else {
01213 dirsep = 0;
01214 p = m;
01215 }
01216 }
01217 *tail = tmp;
01218 tail = &tmp->next;
01219 }
01220
01221 tmp = GLOB_ALLOC(struct glob_pattern);
01222 if (!tmp) {
01223 error:
01224 *tail = 0;
01225 glob_free_pattern(list);
01226 return 0;
01227 }
01228 tmp->type = dirsep ? MATCH_DIR : MATCH_ALL;
01229 tmp->str = 0;
01230 *tail = tmp;
01231 tmp->next = 0;
01232
01233 return list;
01234 }
01235
01236 static void
01237 glob_free_pattern(struct glob_pattern *list)
01238 {
01239 while (list) {
01240 struct glob_pattern *tmp = list;
01241 list = list->next;
01242 if (tmp->str)
01243 GLOB_FREE(tmp->str);
01244 GLOB_FREE(tmp);
01245 }
01246 }
01247
01248 static char *
01249 join_path(const char *path, int dirsep, const char *name)
01250 {
01251 long len = strlen(path);
01252 long len2 = strlen(name)+(dirsep?1:0)+1;
01253 char *buf = GLOB_ALLOC_N(char, len+len2);
01254
01255 if (!buf) return 0;
01256 memcpy(buf, path, len);
01257 if (dirsep) {
01258 buf[len++] = '/';
01259 }
01260 buf[len] = '\0';
01261 strlcat(buf+len, name, len2);
01262 return buf;
01263 }
01264
01265 enum answer { YES, NO, UNKNOWN };
01266
01267 #ifndef S_ISDIR
01268 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
01269 #endif
01270
01271 #ifndef S_ISLNK
01272 # ifndef S_IFLNK
01273 # define S_ISLNK(m) (0)
01274 # else
01275 # define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
01276 # endif
01277 #endif
01278
01279 struct glob_args {
01280 void (*func)(const char *, VALUE, void *);
01281 const char *path;
01282 VALUE value;
01283 rb_encoding *enc;
01284 };
01285
01286 static VALUE
01287 glob_func_caller(VALUE val)
01288 {
01289 struct glob_args *args = (struct glob_args *)val;
01290
01291 (*args->func)(args->path, args->value, args->enc);
01292 return Qnil;
01293 }
01294
01295 #define glob_call_func(func, path, arg, enc) (*(func))((path), (arg), (enc))
01296
01297 static int
01298 glob_helper(
01299 const char *path,
01300 int dirsep,
01301 enum answer exist,
01302 enum answer isdir,
01303 struct glob_pattern **beg,
01304 struct glob_pattern **end,
01305 int flags,
01306 ruby_glob_func *func,
01307 VALUE arg,
01308 rb_encoding *enc)
01309 {
01310 struct stat st;
01311 int status = 0;
01312 struct glob_pattern **cur, **new_beg, **new_end;
01313 int plain = 0, magical = 0, recursive = 0, match_all = 0, match_dir = 0;
01314 int escape = !(flags & FNM_NOESCAPE);
01315
01316 for (cur = beg; cur < end; ++cur) {
01317 struct glob_pattern *p = *cur;
01318 if (p->type == RECURSIVE) {
01319 recursive = 1;
01320 p = p->next;
01321 }
01322 switch (p->type) {
01323 case PLAIN:
01324 plain = 1;
01325 break;
01326 case MAGICAL:
01327 magical = 1;
01328 break;
01329 case MATCH_ALL:
01330 match_all = 1;
01331 break;
01332 case MATCH_DIR:
01333 match_dir = 1;
01334 break;
01335 case RECURSIVE:
01336 rb_bug("continuous RECURSIVEs");
01337 }
01338 }
01339
01340 if (*path) {
01341 if (match_all && exist == UNKNOWN) {
01342 if (do_lstat(path, &st, flags) == 0) {
01343 exist = YES;
01344 isdir = S_ISDIR(st.st_mode) ? YES : S_ISLNK(st.st_mode) ? UNKNOWN : NO;
01345 }
01346 else {
01347 exist = NO;
01348 isdir = NO;
01349 }
01350 }
01351 if (match_dir && isdir == UNKNOWN) {
01352 if (do_stat(path, &st, flags) == 0) {
01353 exist = YES;
01354 isdir = S_ISDIR(st.st_mode) ? YES : NO;
01355 }
01356 else {
01357 exist = NO;
01358 isdir = NO;
01359 }
01360 }
01361 if (match_all && exist == YES) {
01362 status = glob_call_func(func, path, arg, enc);
01363 if (status) return status;
01364 }
01365 if (match_dir && isdir == YES) {
01366 char *tmp = join_path(path, dirsep, "");
01367 if (!tmp) return -1;
01368 status = glob_call_func(func, tmp, arg, enc);
01369 GLOB_FREE(tmp);
01370 if (status) return status;
01371 }
01372 }
01373
01374 if (exist == NO || isdir == NO) return 0;
01375
01376 if (magical || recursive) {
01377 struct dirent *dp;
01378 DIR *dirp;
01379 IF_HAVE_READDIR_R(DEFINE_STRUCT_DIRENT entry);
01380 dirp = do_opendir(*path ? path : ".", flags, enc);
01381 if (dirp == NULL) return 0;
01382
01383 while (READDIR(dirp, enc, &STRUCT_DIRENT(entry), dp)) {
01384 char *buf = join_path(path, dirsep, dp->d_name);
01385 enum answer new_isdir = UNKNOWN;
01386
01387 if (!buf) {
01388 status = -1;
01389 break;
01390 }
01391 if (recursive && strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0
01392 && fnmatch("*", rb_usascii_encoding(), dp->d_name, flags) == 0) {
01393 #ifndef _WIN32
01394 if (do_lstat(buf, &st, flags) == 0)
01395 new_isdir = S_ISDIR(st.st_mode) ? YES : S_ISLNK(st.st_mode) ? UNKNOWN : NO;
01396 else
01397 new_isdir = NO;
01398 #else
01399 new_isdir = dp->d_isdir ? (!dp->d_isrep ? YES : UNKNOWN) : NO;
01400 #endif
01401 }
01402
01403 new_beg = new_end = GLOB_ALLOC_N(struct glob_pattern *, (end - beg) * 2);
01404 if (!new_beg) {
01405 GLOB_FREE(buf);
01406 status = -1;
01407 break;
01408 }
01409
01410 for (cur = beg; cur < end; ++cur) {
01411 struct glob_pattern *p = *cur;
01412 if (p->type == RECURSIVE) {
01413 if (new_isdir == YES)
01414 *new_end++ = p;
01415 p = p->next;
01416 }
01417 if (p->type == PLAIN || p->type == MAGICAL) {
01418 if (fnmatch(p->str, enc, dp->d_name, flags) == 0)
01419 *new_end++ = p->next;
01420 }
01421 }
01422
01423 status = glob_helper(buf, 1, YES, new_isdir, new_beg, new_end,
01424 flags, func, arg, enc);
01425 GLOB_FREE(buf);
01426 GLOB_FREE(new_beg);
01427 if (status) break;
01428 }
01429
01430 closedir(dirp);
01431 }
01432 else if (plain) {
01433 struct glob_pattern **copy_beg, **copy_end, **cur2;
01434
01435 copy_beg = copy_end = GLOB_ALLOC_N(struct glob_pattern *, end - beg);
01436 if (!copy_beg) return -1;
01437 for (cur = beg; cur < end; ++cur)
01438 *copy_end++ = (*cur)->type == PLAIN ? *cur : 0;
01439
01440 for (cur = copy_beg; cur < copy_end; ++cur) {
01441 if (*cur) {
01442 char *buf;
01443 char *name;
01444 size_t len = strlen((*cur)->str) + 1;
01445 name = GLOB_ALLOC_N(char, len);
01446 if (!name) {
01447 status = -1;
01448 break;
01449 }
01450 memcpy(name, (*cur)->str, len);
01451 if (escape) remove_backslashes(name, enc);
01452
01453 new_beg = new_end = GLOB_ALLOC_N(struct glob_pattern *, end - beg);
01454 if (!new_beg) {
01455 GLOB_FREE(name);
01456 status = -1;
01457 break;
01458 }
01459 *new_end++ = (*cur)->next;
01460 for (cur2 = cur + 1; cur2 < copy_end; ++cur2) {
01461 if (*cur2 && fnmatch((*cur2)->str, enc, name, flags) == 0) {
01462 *new_end++ = (*cur2)->next;
01463 *cur2 = 0;
01464 }
01465 }
01466
01467 buf = join_path(path, dirsep, name);
01468 GLOB_FREE(name);
01469 if (!buf) {
01470 GLOB_FREE(new_beg);
01471 status = -1;
01472 break;
01473 }
01474 status = glob_helper(buf, 1, UNKNOWN, UNKNOWN, new_beg,
01475 new_end, flags, func, arg, enc);
01476 GLOB_FREE(buf);
01477 GLOB_FREE(new_beg);
01478 if (status) break;
01479 }
01480 }
01481
01482 GLOB_FREE(copy_beg);
01483 }
01484
01485 return status;
01486 }
01487
01488 static int
01489 ruby_glob0(const char *path, int flags, ruby_glob_func *func, VALUE arg, rb_encoding *enc)
01490 {
01491 struct glob_pattern *list;
01492 const char *root, *start;
01493 char *buf;
01494 size_t n;
01495 int status;
01496
01497 start = root = path;
01498 flags |= FNM_SYSCASE;
01499 #if defined DOSISH
01500 root = rb_path_skip_prefix(root);
01501 #endif
01502
01503 if (root && *root == '/') root++;
01504
01505 n = root - start;
01506 buf = GLOB_ALLOC_N(char, n + 1);
01507 if (!buf) return -1;
01508 MEMCPY(buf, start, char, n);
01509 buf[n] = '\0';
01510
01511 list = glob_make_pattern(root, root + strlen(root), flags, enc);
01512 if (!list) {
01513 GLOB_FREE(buf);
01514 return -1;
01515 }
01516 status = glob_helper(buf, 0, UNKNOWN, UNKNOWN, &list, &list + 1, flags, func, arg, enc);
01517 glob_free_pattern(list);
01518 GLOB_FREE(buf);
01519
01520 return status;
01521 }
01522
01523 int
01524 ruby_glob(const char *path, int flags, ruby_glob_func *func, VALUE arg)
01525 {
01526 return ruby_glob0(path, flags & ~GLOB_VERBOSE, func, arg,
01527 rb_ascii8bit_encoding());
01528 }
01529
01530 static int
01531 rb_glob_caller(const char *path, VALUE a, void *enc)
01532 {
01533 int status;
01534 struct glob_args *args = (struct glob_args *)a;
01535
01536 args->path = path;
01537 rb_protect(glob_func_caller, a, &status);
01538 return status;
01539 }
01540
01541 static int
01542 rb_glob2(const char *path, int flags,
01543 void (*func)(const char *, VALUE, void *), VALUE arg,
01544 rb_encoding* enc)
01545 {
01546 struct glob_args args;
01547
01548 args.func = func;
01549 args.value = arg;
01550 args.enc = enc;
01551
01552 if (flags & FNM_SYSCASE) {
01553 rb_warning("Dir.glob() ignores File::FNM_CASEFOLD");
01554 }
01555
01556 return ruby_glob0(path, flags | GLOB_VERBOSE, rb_glob_caller, (VALUE)&args,
01557 enc);
01558 }
01559
01560 void
01561 rb_glob(const char *path, void (*func)(const char *, VALUE, void *), VALUE arg)
01562 {
01563 int status = rb_glob2(path, 0, func, arg, rb_ascii8bit_encoding());
01564 if (status) GLOB_JUMP_TAG(status);
01565 }
01566
01567 static void
01568 push_pattern(const char *path, VALUE ary, void *enc)
01569 {
01570 rb_ary_push(ary, rb_external_str_new_with_enc(path, strlen(path), enc));
01571 }
01572
01573 static int
01574 ruby_brace_expand(const char *str, int flags, ruby_glob_func *func, VALUE arg,
01575 rb_encoding *enc)
01576 {
01577 const int escape = !(flags & FNM_NOESCAPE);
01578 const char *p = str;
01579 const char *pend = p + strlen(p);
01580 const char *s = p;
01581 const char *lbrace = 0, *rbrace = 0;
01582 int nest = 0, status = 0;
01583
01584 while (*p) {
01585 if (*p == '{' && nest++ == 0) {
01586 lbrace = p;
01587 }
01588 if (*p == '}' && --nest <= 0) {
01589 rbrace = p;
01590 break;
01591 }
01592 if (*p == '\\' && escape) {
01593 if (!*++p) break;
01594 }
01595 Inc(p, pend, enc);
01596 }
01597
01598 if (lbrace && rbrace) {
01599 size_t len = strlen(s) + 1;
01600 char *buf = GLOB_ALLOC_N(char, len);
01601 long shift;
01602
01603 if (!buf) return -1;
01604 memcpy(buf, s, lbrace-s);
01605 shift = (lbrace-s);
01606 p = lbrace;
01607 while (p < rbrace) {
01608 const char *t = ++p;
01609 nest = 0;
01610 while (p < rbrace && !(*p == ',' && nest == 0)) {
01611 if (*p == '{') nest++;
01612 if (*p == '}') nest--;
01613 if (*p == '\\' && escape) {
01614 if (++p == rbrace) break;
01615 }
01616 Inc(p, pend, enc);
01617 }
01618 memcpy(buf+shift, t, p-t);
01619 strlcpy(buf+shift+(p-t), rbrace+1, len-(shift+(p-t)));
01620 status = ruby_brace_expand(buf, flags, func, arg, enc);
01621 if (status) break;
01622 }
01623 GLOB_FREE(buf);
01624 }
01625 else if (!lbrace && !rbrace) {
01626 status = (*func)(s, arg, enc);
01627 }
01628
01629 return status;
01630 }
01631
01632 struct brace_args {
01633 ruby_glob_func *func;
01634 VALUE value;
01635 int flags;
01636 };
01637
01638 static int
01639 glob_brace(const char *path, VALUE val, void *enc)
01640 {
01641 struct brace_args *arg = (struct brace_args *)val;
01642
01643 return ruby_glob0(path, arg->flags, arg->func, arg->value, enc);
01644 }
01645
01646 static int
01647 ruby_brace_glob0(const char *str, int flags, ruby_glob_func *func, VALUE arg,
01648 rb_encoding* enc)
01649 {
01650 struct brace_args args;
01651
01652 args.func = func;
01653 args.value = arg;
01654 args.flags = flags;
01655 return ruby_brace_expand(str, flags, glob_brace, (VALUE)&args, enc);
01656 }
01657
01658 int
01659 ruby_brace_glob(const char *str, int flags, ruby_glob_func *func, VALUE arg)
01660 {
01661 return ruby_brace_glob0(str, flags & ~GLOB_VERBOSE, func, arg,
01662 rb_ascii8bit_encoding());
01663 }
01664
01665 int
01666 ruby_brace_glob_with_enc(const char *str, int flags, ruby_glob_func *func, VALUE arg, rb_encoding *enc)
01667 {
01668 return ruby_brace_glob0(str, flags & ~GLOB_VERBOSE, func, arg, enc);
01669 }
01670
01671 static int
01672 push_glob(VALUE ary, VALUE str, int flags)
01673 {
01674 struct glob_args args;
01675 rb_encoding *enc = rb_enc_get(str);
01676
01677 if (enc == rb_usascii_encoding()) enc = rb_filesystem_encoding();
01678 args.func = push_pattern;
01679 args.value = ary;
01680 args.enc = enc;
01681
01682 RB_GC_GUARD(str);
01683 return ruby_brace_glob0(RSTRING_PTR(str), flags | GLOB_VERBOSE,
01684 rb_glob_caller, (VALUE)&args, enc);
01685 }
01686
01687 static VALUE
01688 rb_push_glob(VALUE str, int flags)
01689 {
01690 long offset = 0;
01691 VALUE ary;
01692
01693 GlobPathValue(str, TRUE);
01694 ary = rb_ary_new();
01695
01696 while (offset < RSTRING_LEN(str)) {
01697 char *p, *pend;
01698 int status;
01699 p = RSTRING_PTR(str) + offset;
01700 status = push_glob(ary, rb_enc_str_new(p, strlen(p), rb_enc_get(str)),
01701 flags);
01702 if (status) GLOB_JUMP_TAG(status);
01703 if (offset >= RSTRING_LEN(str)) break;
01704 p += strlen(p) + 1;
01705 pend = RSTRING_PTR(str) + RSTRING_LEN(str);
01706 while (p < pend && !*p)
01707 p++;
01708 offset = p - RSTRING_PTR(str);
01709 }
01710
01711 return ary;
01712 }
01713
01714 static VALUE
01715 dir_globs(long argc, VALUE *argv, int flags)
01716 {
01717 VALUE ary = rb_ary_new();
01718 long i;
01719
01720 for (i = 0; i < argc; ++i) {
01721 int status;
01722 VALUE str = argv[i];
01723 GlobPathValue(str, TRUE);
01724 status = push_glob(ary, str, flags);
01725 if (status) GLOB_JUMP_TAG(status);
01726 }
01727
01728 return ary;
01729 }
01730
01731
01732
01733
01734
01735
01736
01737
01738
01739
01740
01741 static VALUE
01742 dir_s_aref(int argc, VALUE *argv, VALUE obj)
01743 {
01744 if (argc == 1) {
01745 return rb_push_glob(argv[0], 0);
01746 }
01747 return dir_globs(argc, argv, 0);
01748 }
01749
01750
01751
01752
01753
01754
01755
01756
01757
01758
01759
01760
01761
01762
01763
01764
01765
01766
01767
01768
01769
01770
01771
01772
01773
01774
01775
01776
01777
01778
01779
01780
01781
01782
01783
01784
01785
01786
01787
01788
01789
01790
01791
01792
01793
01794
01795
01796
01797
01798
01799
01800
01801
01802
01803
01804
01805
01806
01807
01808
01809
01810
01811
01812
01813
01814
01815
01816
01817 static VALUE
01818 dir_s_glob(int argc, VALUE *argv, VALUE obj)
01819 {
01820 VALUE str, rflags, ary;
01821 int flags;
01822
01823 if (rb_scan_args(argc, argv, "11", &str, &rflags) == 2)
01824 flags = NUM2INT(rflags);
01825 else
01826 flags = 0;
01827
01828 ary = rb_check_array_type(str);
01829 if (NIL_P(ary)) {
01830 ary = rb_push_glob(str, flags);
01831 }
01832 else {
01833 volatile VALUE v = ary;
01834 ary = dir_globs(RARRAY_LEN(v), RARRAY_PTR(v), flags);
01835 }
01836
01837 if (rb_block_given_p()) {
01838 rb_ary_each(ary);
01839 return Qnil;
01840 }
01841 return ary;
01842 }
01843
01844 static VALUE
01845 dir_open_dir(int argc, VALUE *argv)
01846 {
01847 VALUE dir = rb_funcall2(rb_cDir, rb_intern("open"), argc, argv);
01848 struct dir_data *dirp;
01849
01850 TypedData_Get_Struct(dir, struct dir_data, &dir_data_type, dirp);
01851 return dir;
01852 }
01853
01854
01855
01856
01857
01858
01859
01860
01861
01862
01863
01864
01865
01866
01867
01868
01869
01870
01871
01872
01873
01874
01875 static VALUE
01876 dir_foreach(int argc, VALUE *argv, VALUE io)
01877 {
01878 VALUE dir;
01879
01880 RETURN_ENUMERATOR(io, argc, argv);
01881 dir = dir_open_dir(argc, argv);
01882 rb_ensure(dir_each, dir, dir_close, dir);
01883 return Qnil;
01884 }
01885
01886
01887
01888
01889
01890
01891
01892
01893
01894
01895
01896
01897 static VALUE
01898 dir_entries(int argc, VALUE *argv, VALUE io)
01899 {
01900 VALUE dir;
01901
01902 dir = dir_open_dir(argc, argv);
01903 return rb_ensure(rb_Array, dir, dir_close, dir);
01904 }
01905
01906
01907
01908
01909
01910
01911
01912
01913
01914
01915
01916
01917
01918
01919
01920
01921
01922
01923
01924
01925
01926
01927
01928
01929
01930
01931
01932
01933
01934
01935
01936
01937
01938
01939
01940
01941
01942
01943
01944
01945
01946
01947
01948
01949
01950
01951
01952
01953
01954
01955
01956
01957
01958
01959
01960
01961
01962
01963
01964
01965
01966
01967
01968
01969
01970
01971
01972
01973
01974
01975
01976
01977
01978
01979
01980
01981
01982
01983
01984
01985
01986
01987 static VALUE
01988 file_s_fnmatch(int argc, VALUE *argv, VALUE obj)
01989 {
01990 VALUE pattern, path;
01991 VALUE rflags;
01992 int flags;
01993
01994 if (rb_scan_args(argc, argv, "21", &pattern, &path, &rflags) == 3)
01995 flags = NUM2INT(rflags);
01996 else
01997 flags = 0;
01998
01999 StringValue(pattern);
02000 FilePathStringValue(path);
02001
02002 if (fnmatch(RSTRING_PTR(pattern), rb_enc_get(pattern), RSTRING_PTR(path),
02003 flags) == 0)
02004 return Qtrue;
02005
02006 return Qfalse;
02007 }
02008
02009
02010
02011
02012
02013
02014
02015
02016
02017 static VALUE
02018 dir_s_home(int argc, VALUE *argv, VALUE obj)
02019 {
02020 VALUE user;
02021 const char *u = 0;
02022
02023 rb_scan_args(argc, argv, "01", &user);
02024 if (!NIL_P(user)) {
02025 SafeStringValue(user);
02026 u = StringValueCStr(user);
02027 }
02028 return rb_home_dir(u, rb_str_new(0, 0));
02029 }
02030
02031
02032
02033
02034
02035
02036
02037
02038
02039
02040
02041
02042 void
02043 Init_Dir(void)
02044 {
02045 rb_cDir = rb_define_class("Dir", rb_cObject);
02046
02047 rb_include_module(rb_cDir, rb_mEnumerable);
02048
02049 rb_define_alloc_func(rb_cDir, dir_s_alloc);
02050 rb_define_singleton_method(rb_cDir, "open", dir_s_open, -1);
02051 rb_define_singleton_method(rb_cDir, "foreach", dir_foreach, -1);
02052 rb_define_singleton_method(rb_cDir, "entries", dir_entries, -1);
02053
02054 rb_define_method(rb_cDir,"initialize", dir_initialize, -1);
02055 rb_define_method(rb_cDir,"path", dir_path, 0);
02056 rb_define_method(rb_cDir,"to_path", dir_path, 0);
02057 rb_define_method(rb_cDir,"inspect", dir_inspect, 0);
02058 rb_define_method(rb_cDir,"read", dir_read, 0);
02059 rb_define_method(rb_cDir,"each", dir_each, 0);
02060 rb_define_method(rb_cDir,"rewind", dir_rewind, 0);
02061 rb_define_method(rb_cDir,"tell", dir_tell, 0);
02062 rb_define_method(rb_cDir,"seek", dir_seek, 1);
02063 rb_define_method(rb_cDir,"pos", dir_tell, 0);
02064 rb_define_method(rb_cDir,"pos=", dir_set_pos, 1);
02065 rb_define_method(rb_cDir,"close", dir_close, 0);
02066
02067 rb_define_singleton_method(rb_cDir,"chdir", dir_s_chdir, -1);
02068 rb_define_singleton_method(rb_cDir,"getwd", dir_s_getwd, 0);
02069 rb_define_singleton_method(rb_cDir,"pwd", dir_s_getwd, 0);
02070 rb_define_singleton_method(rb_cDir,"chroot", dir_s_chroot, 1);
02071 rb_define_singleton_method(rb_cDir,"mkdir", dir_s_mkdir, -1);
02072 rb_define_singleton_method(rb_cDir,"rmdir", dir_s_rmdir, 1);
02073 rb_define_singleton_method(rb_cDir,"delete", dir_s_rmdir, 1);
02074 rb_define_singleton_method(rb_cDir,"unlink", dir_s_rmdir, 1);
02075 rb_define_singleton_method(rb_cDir,"home", dir_s_home, -1);
02076
02077 rb_define_singleton_method(rb_cDir,"glob", dir_s_glob, -1);
02078 rb_define_singleton_method(rb_cDir,"[]", dir_s_aref, -1);
02079 rb_define_singleton_method(rb_cDir,"exist?", rb_file_directory_p, 1);
02080 rb_define_singleton_method(rb_cDir,"exists?", rb_file_directory_p, 1);
02081
02082 rb_define_singleton_method(rb_cFile,"fnmatch", file_s_fnmatch, -1);
02083 rb_define_singleton_method(rb_cFile,"fnmatch?", file_s_fnmatch, -1);
02084
02085 rb_file_const("FNM_NOESCAPE", INT2FIX(FNM_NOESCAPE));
02086 rb_file_const("FNM_PATHNAME", INT2FIX(FNM_PATHNAME));
02087 rb_file_const("FNM_DOTMATCH", INT2FIX(FNM_DOTMATCH));
02088 rb_file_const("FNM_CASEFOLD", INT2FIX(FNM_CASEFOLD));
02089 rb_file_const("FNM_SYSCASE", INT2FIX(FNM_SYSCASE));
02090 }
02091