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 int recursive = 0;
01179
01180 while (p < e && *p) {
01181 tmp = GLOB_ALLOC(struct glob_pattern);
01182 if (!tmp) goto error;
01183 if (p[0] == '*' && p[1] == '*' && p[2] == '/') {
01184
01185 do { p += 3; while (*p == '/') p++; } while (p[0] == '*' && p[1] == '*' && p[2] == '/');
01186 tmp->type = RECURSIVE;
01187 tmp->str = 0;
01188 dirsep = 1;
01189 recursive = 1;
01190 }
01191 else {
01192 const char *m = find_dirsep(p, e, flags, enc);
01193 int magic = has_magic(p, m, flags, enc);
01194 char *buf;
01195
01196 if (!magic && !recursive && *m) {
01197 const char *m2;
01198 while (!has_magic(m+1, m2 = find_dirsep(m+1, e, flags, enc), flags, enc) &&
01199 *m2) {
01200 m = m2;
01201 }
01202 }
01203 buf = GLOB_ALLOC_N(char, m-p+1);
01204 if (!buf) {
01205 GLOB_FREE(tmp);
01206 goto error;
01207 }
01208 memcpy(buf, p, m-p);
01209 buf[m-p] = '\0';
01210 tmp->type = magic ? MAGICAL : PLAIN;
01211 tmp->str = buf;
01212 if (*m) {
01213 dirsep = 1;
01214 p = m + 1;
01215 }
01216 else {
01217 dirsep = 0;
01218 p = m;
01219 }
01220 }
01221 *tail = tmp;
01222 tail = &tmp->next;
01223 }
01224
01225 tmp = GLOB_ALLOC(struct glob_pattern);
01226 if (!tmp) {
01227 error:
01228 *tail = 0;
01229 glob_free_pattern(list);
01230 return 0;
01231 }
01232 tmp->type = dirsep ? MATCH_DIR : MATCH_ALL;
01233 tmp->str = 0;
01234 *tail = tmp;
01235 tmp->next = 0;
01236
01237 return list;
01238 }
01239
01240 static void
01241 glob_free_pattern(struct glob_pattern *list)
01242 {
01243 while (list) {
01244 struct glob_pattern *tmp = list;
01245 list = list->next;
01246 if (tmp->str)
01247 GLOB_FREE(tmp->str);
01248 GLOB_FREE(tmp);
01249 }
01250 }
01251
01252 static char *
01253 join_path(const char *path, int dirsep, const char *name)
01254 {
01255 long len = strlen(path);
01256 long len2 = strlen(name)+(dirsep?1:0)+1;
01257 char *buf = GLOB_ALLOC_N(char, len+len2);
01258
01259 if (!buf) return 0;
01260 memcpy(buf, path, len);
01261 if (dirsep) {
01262 buf[len++] = '/';
01263 }
01264 buf[len] = '\0';
01265 strlcat(buf+len, name, len2);
01266 return buf;
01267 }
01268
01269 enum answer { YES, NO, UNKNOWN };
01270
01271 #ifndef S_ISDIR
01272 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
01273 #endif
01274
01275 #ifndef S_ISLNK
01276 # ifndef S_IFLNK
01277 # define S_ISLNK(m) (0)
01278 # else
01279 # define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
01280 # endif
01281 #endif
01282
01283 struct glob_args {
01284 void (*func)(const char *, VALUE, void *);
01285 const char *path;
01286 VALUE value;
01287 rb_encoding *enc;
01288 };
01289
01290 static VALUE
01291 glob_func_caller(VALUE val)
01292 {
01293 struct glob_args *args = (struct glob_args *)val;
01294
01295 (*args->func)(args->path, args->value, args->enc);
01296 return Qnil;
01297 }
01298
01299 #define glob_call_func(func, path, arg, enc) (*(func))((path), (arg), (enc))
01300
01301 static int
01302 glob_helper(
01303 const char *path,
01304 int dirsep,
01305 enum answer exist,
01306 enum answer isdir,
01307 struct glob_pattern **beg,
01308 struct glob_pattern **end,
01309 int flags,
01310 ruby_glob_func *func,
01311 VALUE arg,
01312 rb_encoding *enc)
01313 {
01314 struct stat st;
01315 int status = 0;
01316 struct glob_pattern **cur, **new_beg, **new_end;
01317 int plain = 0, magical = 0, recursive = 0, match_all = 0, match_dir = 0;
01318 int escape = !(flags & FNM_NOESCAPE);
01319
01320 for (cur = beg; cur < end; ++cur) {
01321 struct glob_pattern *p = *cur;
01322 if (p->type == RECURSIVE) {
01323 recursive = 1;
01324 p = p->next;
01325 }
01326 switch (p->type) {
01327 case PLAIN:
01328 plain = 1;
01329 break;
01330 case MAGICAL:
01331 magical = 1;
01332 break;
01333 case MATCH_ALL:
01334 match_all = 1;
01335 break;
01336 case MATCH_DIR:
01337 match_dir = 1;
01338 break;
01339 case RECURSIVE:
01340 rb_bug("continuous RECURSIVEs");
01341 }
01342 }
01343
01344 if (*path) {
01345 if (match_all && exist == UNKNOWN) {
01346 if (do_lstat(path, &st, flags) == 0) {
01347 exist = YES;
01348 isdir = S_ISDIR(st.st_mode) ? YES : S_ISLNK(st.st_mode) ? UNKNOWN : NO;
01349 }
01350 else {
01351 exist = NO;
01352 isdir = NO;
01353 }
01354 }
01355 if (match_dir && isdir == UNKNOWN) {
01356 if (do_stat(path, &st, flags) == 0) {
01357 exist = YES;
01358 isdir = S_ISDIR(st.st_mode) ? YES : NO;
01359 }
01360 else {
01361 exist = NO;
01362 isdir = NO;
01363 }
01364 }
01365 if (match_all && exist == YES) {
01366 status = glob_call_func(func, path, arg, enc);
01367 if (status) return status;
01368 }
01369 if (match_dir && isdir == YES) {
01370 char *tmp = join_path(path, dirsep, "");
01371 if (!tmp) return -1;
01372 status = glob_call_func(func, tmp, arg, enc);
01373 GLOB_FREE(tmp);
01374 if (status) return status;
01375 }
01376 }
01377
01378 if (exist == NO || isdir == NO) return 0;
01379
01380 if (magical || recursive) {
01381 struct dirent *dp;
01382 DIR *dirp;
01383 IF_HAVE_READDIR_R(DEFINE_STRUCT_DIRENT entry);
01384 dirp = do_opendir(*path ? path : ".", flags, enc);
01385 if (dirp == NULL) return 0;
01386
01387 while (READDIR(dirp, enc, &STRUCT_DIRENT(entry), dp)) {
01388 char *buf = join_path(path, dirsep, dp->d_name);
01389 enum answer new_isdir = UNKNOWN;
01390
01391 if (!buf) {
01392 status = -1;
01393 break;
01394 }
01395 if (recursive && strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0
01396 && fnmatch("*", rb_usascii_encoding(), dp->d_name, flags) == 0) {
01397 #ifndef _WIN32
01398 if (do_lstat(buf, &st, flags) == 0)
01399 new_isdir = S_ISDIR(st.st_mode) ? YES : S_ISLNK(st.st_mode) ? UNKNOWN : NO;
01400 else
01401 new_isdir = NO;
01402 #else
01403 new_isdir = dp->d_isdir ? (!dp->d_isrep ? YES : UNKNOWN) : NO;
01404 #endif
01405 }
01406
01407 new_beg = new_end = GLOB_ALLOC_N(struct glob_pattern *, (end - beg) * 2);
01408 if (!new_beg) {
01409 GLOB_FREE(buf);
01410 status = -1;
01411 break;
01412 }
01413
01414 for (cur = beg; cur < end; ++cur) {
01415 struct glob_pattern *p = *cur;
01416 if (p->type == RECURSIVE) {
01417 if (new_isdir == YES)
01418 *new_end++ = p;
01419 p = p->next;
01420 }
01421 if (p->type == PLAIN || p->type == MAGICAL) {
01422 if (fnmatch(p->str, enc, dp->d_name, flags) == 0)
01423 *new_end++ = p->next;
01424 }
01425 }
01426
01427 status = glob_helper(buf, 1, YES, new_isdir, new_beg, new_end,
01428 flags, func, arg, enc);
01429 GLOB_FREE(buf);
01430 GLOB_FREE(new_beg);
01431 if (status) break;
01432 }
01433
01434 closedir(dirp);
01435 }
01436 else if (plain) {
01437 struct glob_pattern **copy_beg, **copy_end, **cur2;
01438
01439 copy_beg = copy_end = GLOB_ALLOC_N(struct glob_pattern *, end - beg);
01440 if (!copy_beg) return -1;
01441 for (cur = beg; cur < end; ++cur)
01442 *copy_end++ = (*cur)->type == PLAIN ? *cur : 0;
01443
01444 for (cur = copy_beg; cur < copy_end; ++cur) {
01445 if (*cur) {
01446 char *buf;
01447 char *name;
01448 size_t len = strlen((*cur)->str) + 1;
01449 name = GLOB_ALLOC_N(char, len);
01450 if (!name) {
01451 status = -1;
01452 break;
01453 }
01454 memcpy(name, (*cur)->str, len);
01455 if (escape) remove_backslashes(name, enc);
01456
01457 new_beg = new_end = GLOB_ALLOC_N(struct glob_pattern *, end - beg);
01458 if (!new_beg) {
01459 GLOB_FREE(name);
01460 status = -1;
01461 break;
01462 }
01463 *new_end++ = (*cur)->next;
01464 for (cur2 = cur + 1; cur2 < copy_end; ++cur2) {
01465 if (*cur2 && fnmatch((*cur2)->str, enc, name, flags) == 0) {
01466 *new_end++ = (*cur2)->next;
01467 *cur2 = 0;
01468 }
01469 }
01470
01471 buf = join_path(path, dirsep, name);
01472 GLOB_FREE(name);
01473 if (!buf) {
01474 GLOB_FREE(new_beg);
01475 status = -1;
01476 break;
01477 }
01478 status = glob_helper(buf, 1, UNKNOWN, UNKNOWN, new_beg,
01479 new_end, flags, func, arg, enc);
01480 GLOB_FREE(buf);
01481 GLOB_FREE(new_beg);
01482 if (status) break;
01483 }
01484 }
01485
01486 GLOB_FREE(copy_beg);
01487 }
01488
01489 return status;
01490 }
01491
01492 static int
01493 ruby_glob0(const char *path, int flags, ruby_glob_func *func, VALUE arg, rb_encoding *enc)
01494 {
01495 struct glob_pattern *list;
01496 const char *root, *start;
01497 char *buf;
01498 size_t n;
01499 int status;
01500
01501 start = root = path;
01502 flags |= FNM_SYSCASE;
01503 #if defined DOSISH
01504 root = rb_enc_path_skip_prefix(root, root + strlen(root), enc);
01505 #endif
01506
01507 if (root && *root == '/') root++;
01508
01509 n = root - start;
01510 buf = GLOB_ALLOC_N(char, n + 1);
01511 if (!buf) return -1;
01512 MEMCPY(buf, start, char, n);
01513 buf[n] = '\0';
01514
01515 list = glob_make_pattern(root, root + strlen(root), flags, enc);
01516 if (!list) {
01517 GLOB_FREE(buf);
01518 return -1;
01519 }
01520 status = glob_helper(buf, 0, UNKNOWN, UNKNOWN, &list, &list + 1, flags, func, arg, enc);
01521 glob_free_pattern(list);
01522 GLOB_FREE(buf);
01523
01524 return status;
01525 }
01526
01527 int
01528 ruby_glob(const char *path, int flags, ruby_glob_func *func, VALUE arg)
01529 {
01530 return ruby_glob0(path, flags & ~GLOB_VERBOSE, func, arg,
01531 rb_ascii8bit_encoding());
01532 }
01533
01534 static int
01535 rb_glob_caller(const char *path, VALUE a, void *enc)
01536 {
01537 int status;
01538 struct glob_args *args = (struct glob_args *)a;
01539
01540 args->path = path;
01541 rb_protect(glob_func_caller, a, &status);
01542 return status;
01543 }
01544
01545 static int
01546 rb_glob2(const char *path, int flags,
01547 void (*func)(const char *, VALUE, void *), VALUE arg,
01548 rb_encoding* enc)
01549 {
01550 struct glob_args args;
01551
01552 args.func = func;
01553 args.value = arg;
01554 args.enc = enc;
01555
01556 if (flags & FNM_SYSCASE) {
01557 rb_warning("Dir.glob() ignores File::FNM_CASEFOLD");
01558 }
01559
01560 return ruby_glob0(path, flags | GLOB_VERBOSE, rb_glob_caller, (VALUE)&args,
01561 enc);
01562 }
01563
01564 void
01565 rb_glob(const char *path, void (*func)(const char *, VALUE, void *), VALUE arg)
01566 {
01567 int status = rb_glob2(path, 0, func, arg, rb_ascii8bit_encoding());
01568 if (status) GLOB_JUMP_TAG(status);
01569 }
01570
01571 static void
01572 push_pattern(const char *path, VALUE ary, void *enc)
01573 {
01574 rb_ary_push(ary, rb_external_str_new_with_enc(path, strlen(path), enc));
01575 }
01576
01577 static int
01578 ruby_brace_expand(const char *str, int flags, ruby_glob_func *func, VALUE arg,
01579 rb_encoding *enc)
01580 {
01581 const int escape = !(flags & FNM_NOESCAPE);
01582 const char *p = str;
01583 const char *pend = p + strlen(p);
01584 const char *s = p;
01585 const char *lbrace = 0, *rbrace = 0;
01586 int nest = 0, status = 0;
01587
01588 while (*p) {
01589 if (*p == '{' && nest++ == 0) {
01590 lbrace = p;
01591 }
01592 if (*p == '}' && --nest <= 0) {
01593 rbrace = p;
01594 break;
01595 }
01596 if (*p == '\\' && escape) {
01597 if (!*++p) break;
01598 }
01599 Inc(p, pend, enc);
01600 }
01601
01602 if (lbrace && rbrace) {
01603 size_t len = strlen(s) + 1;
01604 char *buf = GLOB_ALLOC_N(char, len);
01605 long shift;
01606
01607 if (!buf) return -1;
01608 memcpy(buf, s, lbrace-s);
01609 shift = (lbrace-s);
01610 p = lbrace;
01611 while (p < rbrace) {
01612 const char *t = ++p;
01613 nest = 0;
01614 while (p < rbrace && !(*p == ',' && nest == 0)) {
01615 if (*p == '{') nest++;
01616 if (*p == '}') nest--;
01617 if (*p == '\\' && escape) {
01618 if (++p == rbrace) break;
01619 }
01620 Inc(p, pend, enc);
01621 }
01622 memcpy(buf+shift, t, p-t);
01623 strlcpy(buf+shift+(p-t), rbrace+1, len-(shift+(p-t)));
01624 status = ruby_brace_expand(buf, flags, func, arg, enc);
01625 if (status) break;
01626 }
01627 GLOB_FREE(buf);
01628 }
01629 else if (!lbrace && !rbrace) {
01630 status = (*func)(s, arg, enc);
01631 }
01632
01633 return status;
01634 }
01635
01636 struct brace_args {
01637 ruby_glob_func *func;
01638 VALUE value;
01639 int flags;
01640 };
01641
01642 static int
01643 glob_brace(const char *path, VALUE val, void *enc)
01644 {
01645 struct brace_args *arg = (struct brace_args *)val;
01646
01647 return ruby_glob0(path, arg->flags, arg->func, arg->value, enc);
01648 }
01649
01650 static int
01651 ruby_brace_glob0(const char *str, int flags, ruby_glob_func *func, VALUE arg,
01652 rb_encoding* enc)
01653 {
01654 struct brace_args args;
01655
01656 args.func = func;
01657 args.value = arg;
01658 args.flags = flags;
01659 return ruby_brace_expand(str, flags, glob_brace, (VALUE)&args, enc);
01660 }
01661
01662 int
01663 ruby_brace_glob(const char *str, int flags, ruby_glob_func *func, VALUE arg)
01664 {
01665 return ruby_brace_glob0(str, flags & ~GLOB_VERBOSE, func, arg,
01666 rb_ascii8bit_encoding());
01667 }
01668
01669 int
01670 ruby_brace_glob_with_enc(const char *str, int flags, ruby_glob_func *func, VALUE arg, rb_encoding *enc)
01671 {
01672 return ruby_brace_glob0(str, flags & ~GLOB_VERBOSE, func, arg, enc);
01673 }
01674
01675 static int
01676 push_glob(VALUE ary, VALUE str, int flags)
01677 {
01678 struct glob_args args;
01679 rb_encoding *enc = rb_enc_get(str);
01680
01681 if (enc == rb_usascii_encoding()) enc = rb_filesystem_encoding();
01682 args.func = push_pattern;
01683 args.value = ary;
01684 args.enc = enc;
01685
01686 RB_GC_GUARD(str);
01687 return ruby_brace_glob0(RSTRING_PTR(str), flags | GLOB_VERBOSE,
01688 rb_glob_caller, (VALUE)&args, enc);
01689 }
01690
01691 static VALUE
01692 rb_push_glob(VALUE str, int flags)
01693 {
01694 long offset = 0;
01695 VALUE ary;
01696
01697 GlobPathValue(str, TRUE);
01698 ary = rb_ary_new();
01699
01700 while (offset < RSTRING_LEN(str)) {
01701 char *p, *pend;
01702 int status;
01703 p = RSTRING_PTR(str) + offset;
01704 status = push_glob(ary, rb_enc_str_new(p, strlen(p), rb_enc_get(str)),
01705 flags);
01706 if (status) GLOB_JUMP_TAG(status);
01707 if (offset >= RSTRING_LEN(str)) break;
01708 p += strlen(p) + 1;
01709 pend = RSTRING_PTR(str) + RSTRING_LEN(str);
01710 while (p < pend && !*p)
01711 p++;
01712 offset = p - RSTRING_PTR(str);
01713 }
01714
01715 return ary;
01716 }
01717
01718 static VALUE
01719 dir_globs(long argc, VALUE *argv, int flags)
01720 {
01721 VALUE ary = rb_ary_new();
01722 long i;
01723
01724 for (i = 0; i < argc; ++i) {
01725 int status;
01726 VALUE str = argv[i];
01727 GlobPathValue(str, TRUE);
01728 status = push_glob(ary, str, flags);
01729 if (status) GLOB_JUMP_TAG(status);
01730 }
01731
01732 return ary;
01733 }
01734
01735
01736
01737
01738
01739
01740
01741
01742
01743
01744
01745 static VALUE
01746 dir_s_aref(int argc, VALUE *argv, VALUE obj)
01747 {
01748 if (argc == 1) {
01749 return rb_push_glob(argv[0], 0);
01750 }
01751 return dir_globs(argc, argv, 0);
01752 }
01753
01754
01755
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
01820
01821 static VALUE
01822 dir_s_glob(int argc, VALUE *argv, VALUE obj)
01823 {
01824 VALUE str, rflags, ary;
01825 int flags;
01826
01827 if (rb_scan_args(argc, argv, "11", &str, &rflags) == 2)
01828 flags = NUM2INT(rflags);
01829 else
01830 flags = 0;
01831
01832 ary = rb_check_array_type(str);
01833 if (NIL_P(ary)) {
01834 ary = rb_push_glob(str, flags);
01835 }
01836 else {
01837 volatile VALUE v = ary;
01838 ary = dir_globs(RARRAY_LEN(v), RARRAY_PTR(v), flags);
01839 }
01840
01841 if (rb_block_given_p()) {
01842 rb_ary_each(ary);
01843 return Qnil;
01844 }
01845 return ary;
01846 }
01847
01848 static VALUE
01849 dir_open_dir(int argc, VALUE *argv)
01850 {
01851 VALUE dir = rb_funcall2(rb_cDir, rb_intern("open"), argc, argv);
01852 struct dir_data *dirp;
01853
01854 TypedData_Get_Struct(dir, struct dir_data, &dir_data_type, dirp);
01855 return dir;
01856 }
01857
01858
01859
01860
01861
01862
01863
01864
01865
01866
01867
01868
01869
01870
01871
01872
01873
01874
01875
01876
01877
01878
01879 static VALUE
01880 dir_foreach(int argc, VALUE *argv, VALUE io)
01881 {
01882 VALUE dir;
01883
01884 RETURN_ENUMERATOR(io, argc, argv);
01885 dir = dir_open_dir(argc, argv);
01886 rb_ensure(dir_each, dir, dir_close, dir);
01887 return Qnil;
01888 }
01889
01890
01891
01892
01893
01894
01895
01896
01897
01898
01899
01900
01901 static VALUE
01902 dir_entries(int argc, VALUE *argv, VALUE io)
01903 {
01904 VALUE dir;
01905
01906 dir = dir_open_dir(argc, argv);
01907 return rb_ensure(rb_Array, dir, dir_close, dir);
01908 }
01909
01910
01911
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
01990
01991 static VALUE
01992 file_s_fnmatch(int argc, VALUE *argv, VALUE obj)
01993 {
01994 VALUE pattern, path;
01995 VALUE rflags;
01996 int flags;
01997
01998 if (rb_scan_args(argc, argv, "21", &pattern, &path, &rflags) == 3)
01999 flags = NUM2INT(rflags);
02000 else
02001 flags = 0;
02002
02003 StringValue(pattern);
02004 FilePathStringValue(path);
02005
02006 if (fnmatch(RSTRING_PTR(pattern), rb_enc_get(pattern), RSTRING_PTR(path),
02007 flags) == 0)
02008 return Qtrue;
02009
02010 return Qfalse;
02011 }
02012
02013
02014
02015
02016
02017
02018
02019
02020
02021 static VALUE
02022 dir_s_home(int argc, VALUE *argv, VALUE obj)
02023 {
02024 VALUE user;
02025 const char *u = 0;
02026
02027 rb_scan_args(argc, argv, "01", &user);
02028 if (!NIL_P(user)) {
02029 SafeStringValue(user);
02030 u = StringValueCStr(user);
02031 }
02032 return rb_home_dir(u, rb_str_new(0, 0));
02033 }
02034
02035
02036
02037
02038
02039
02040
02041
02042
02043
02044
02045
02046 void
02047 Init_Dir(void)
02048 {
02049 rb_cDir = rb_define_class("Dir", rb_cObject);
02050
02051 rb_include_module(rb_cDir, rb_mEnumerable);
02052
02053 rb_define_alloc_func(rb_cDir, dir_s_alloc);
02054 rb_define_singleton_method(rb_cDir, "open", dir_s_open, -1);
02055 rb_define_singleton_method(rb_cDir, "foreach", dir_foreach, -1);
02056 rb_define_singleton_method(rb_cDir, "entries", dir_entries, -1);
02057
02058 rb_define_method(rb_cDir,"initialize", dir_initialize, -1);
02059 rb_define_method(rb_cDir,"path", dir_path, 0);
02060 rb_define_method(rb_cDir,"to_path", dir_path, 0);
02061 rb_define_method(rb_cDir,"inspect", dir_inspect, 0);
02062 rb_define_method(rb_cDir,"read", dir_read, 0);
02063 rb_define_method(rb_cDir,"each", dir_each, 0);
02064 rb_define_method(rb_cDir,"rewind", dir_rewind, 0);
02065 rb_define_method(rb_cDir,"tell", dir_tell, 0);
02066 rb_define_method(rb_cDir,"seek", dir_seek, 1);
02067 rb_define_method(rb_cDir,"pos", dir_tell, 0);
02068 rb_define_method(rb_cDir,"pos=", dir_set_pos, 1);
02069 rb_define_method(rb_cDir,"close", dir_close, 0);
02070
02071 rb_define_singleton_method(rb_cDir,"chdir", dir_s_chdir, -1);
02072 rb_define_singleton_method(rb_cDir,"getwd", dir_s_getwd, 0);
02073 rb_define_singleton_method(rb_cDir,"pwd", dir_s_getwd, 0);
02074 rb_define_singleton_method(rb_cDir,"chroot", dir_s_chroot, 1);
02075 rb_define_singleton_method(rb_cDir,"mkdir", dir_s_mkdir, -1);
02076 rb_define_singleton_method(rb_cDir,"rmdir", dir_s_rmdir, 1);
02077 rb_define_singleton_method(rb_cDir,"delete", dir_s_rmdir, 1);
02078 rb_define_singleton_method(rb_cDir,"unlink", dir_s_rmdir, 1);
02079 rb_define_singleton_method(rb_cDir,"home", dir_s_home, -1);
02080
02081 rb_define_singleton_method(rb_cDir,"glob", dir_s_glob, -1);
02082 rb_define_singleton_method(rb_cDir,"[]", dir_s_aref, -1);
02083 rb_define_singleton_method(rb_cDir,"exist?", rb_file_directory_p, 1);
02084 rb_define_singleton_method(rb_cDir,"exists?", rb_file_directory_p, 1);
02085
02086 rb_define_singleton_method(rb_cFile,"fnmatch", file_s_fnmatch, -1);
02087 rb_define_singleton_method(rb_cFile,"fnmatch?", file_s_fnmatch, -1);
02088
02089 rb_file_const("FNM_NOESCAPE", INT2FIX(FNM_NOESCAPE));
02090 rb_file_const("FNM_PATHNAME", INT2FIX(FNM_PATHNAME));
02091 rb_file_const("FNM_DOTMATCH", INT2FIX(FNM_DOTMATCH));
02092 rb_file_const("FNM_CASEFOLD", INT2FIX(FNM_CASEFOLD));
02093 rb_file_const("FNM_SYSCASE", INT2FIX(FNM_SYSCASE));
02094 }
02095