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