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