00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "ruby/ruby.h"
00015 #include "ruby/encoding.h"
00016
00017 #include <sys/types.h>
00018 #include <sys/stat.h>
00019
00020 #ifdef HAVE_UNISTD_H
00021 #include <unistd.h>
00022 #endif
00023
00024 #if defined HAVE_DIRENT_H && !defined _WIN32
00025 # include <dirent.h>
00026 # define NAMLEN(dirent) strlen((dirent)->d_name)
00027 #elif defined HAVE_DIRECT_H && !defined _WIN32
00028 # include <direct.h>
00029 # define NAMLEN(dirent) strlen((dirent)->d_name)
00030 #else
00031 # define dirent direct
00032 # if !defined __NeXT__
00033 # define NAMLEN(dirent) (dirent)->d_namlen
00034 # else
00035 #
00036 # define NAMLEN(dirent) strlen((dirent)->d_name)
00037 # endif
00038 # if HAVE_SYS_NDIR_H
00039 # include <sys/ndir.h>
00040 # endif
00041 # if HAVE_SYS_DIR_H
00042 # include <sys/dir.h>
00043 # endif
00044 # if HAVE_NDIR_H
00045 # include <ndir.h>
00046 # endif
00047 # ifdef _WIN32
00048 # include "win32/dir.h"
00049 # endif
00050 #endif
00051
00052 #include <errno.h>
00053
00054 #ifndef HAVE_STDLIB_H
00055 char *getenv();
00056 #endif
00057
00058 #ifndef HAVE_STRING_H
00059 char *strchr(char*,char);
00060 #endif
00061
00062 #include <ctype.h>
00063
00064 #include "ruby/util.h"
00065
00066 #if !defined HAVE_LSTAT && !defined lstat
00067 #define lstat stat
00068 #endif
00069
00070
00071 #ifdef _WIN32
00072 #undef chdir
00073 #define chdir(p) rb_w32_uchdir(p)
00074 #undef mkdir
00075 #define mkdir(p, m) rb_w32_umkdir(p, m)
00076 #undef rmdir
00077 #define rmdir(p) rb_w32_urmdir(p)
00078 #endif
00079
00080 #define FNM_NOESCAPE 0x01
00081 #define FNM_PATHNAME 0x02
00082 #define FNM_DOTMATCH 0x04
00083 #define FNM_CASEFOLD 0x08
00084 #if CASEFOLD_FILESYSTEM
00085 #define FNM_SYSCASE FNM_CASEFOLD
00086 #else
00087 #define FNM_SYSCASE 0
00088 #endif
00089
00090 #define FNM_NOMATCH 1
00091 #define FNM_ERROR 2
00092
00093 # define Next(p, e, enc) (p + rb_enc_mbclen(p, e, enc))
00094 # define Inc(p, e, enc) ((p) = Next(p, e, enc))
00095
00096 static char *
00097 bracket(
00098 const char *p,
00099 const char *pend,
00100 const char *s,
00101 const char *send,
00102 int flags,
00103 rb_encoding *enc)
00104 {
00105 const int nocase = flags & FNM_CASEFOLD;
00106 const int escape = !(flags & FNM_NOESCAPE);
00107 unsigned int c1, c2;
00108 int r;
00109 int ok = 0, not = 0;
00110
00111 if (*p == '!' || *p == '^') {
00112 not = 1;
00113 p++;
00114 }
00115
00116 while (*p != ']') {
00117 const char *t1 = p;
00118 if (escape && *t1 == '\\')
00119 t1++;
00120 if (!*t1)
00121 return NULL;
00122 p = t1 + (r = rb_enc_mbclen(t1, pend, enc));
00123 if (p[0] == '-' && p[1] != ']') {
00124 const char *t2 = p + 1;
00125 int r2;
00126 if (escape && *t2 == '\\')
00127 t2++;
00128 if (!*t2)
00129 return NULL;
00130 p = t2 + (r2 = rb_enc_mbclen(t2, pend, enc));
00131 if (ok) continue;
00132 if ((r <= (send-s) && memcmp(t1, s, r) == 0) ||
00133 (r2 <= (send-s) && memcmp(t2, s, r) == 0)) {
00134 ok = 1;
00135 continue;
00136 }
00137 c1 = rb_enc_codepoint(s, send, enc);
00138 if (nocase) c1 = rb_enc_toupper(c1, enc);
00139 c2 = rb_enc_codepoint(t1, pend, enc);
00140 if (nocase) c2 = rb_enc_toupper(c2, enc);
00141 if (c1 < c2) continue;
00142 c2 = rb_enc_codepoint(t2, pend, enc);
00143 if (nocase) c2 = rb_enc_toupper(c2, enc);
00144 if (c1 > c2) continue;
00145 }
00146 else {
00147 if (ok) continue;
00148 if (r <= (send-s) && memcmp(t1, s, r) == 0) {
00149 ok = 1;
00150 continue;
00151 }
00152 if (!nocase) continue;
00153 c1 = rb_enc_toupper(rb_enc_codepoint(s, send, enc), enc);
00154 c2 = rb_enc_toupper(rb_enc_codepoint(p, pend, enc), enc);
00155 if (c1 != c2) continue;
00156 }
00157 ok = 1;
00158 }
00159
00160 return ok == not ? NULL : (char *)p + 1;
00161 }
00162
00163
00164
00165
00166
00167
00168 #define UNESCAPE(p) (escape && *(p) == '\\' ? (p) + 1 : (p))
00169 #define ISEND(p) (!*(p) || (pathname && *(p) == '/'))
00170 #define RETURN(val) return *pcur = p, *scur = s, (val);
00171
00172 static int
00173 fnmatch_helper(
00174 const char **pcur,
00175 const char **scur,
00176 int flags,
00177 rb_encoding *enc)
00178 {
00179 const int period = !(flags & FNM_DOTMATCH);
00180 const int pathname = flags & FNM_PATHNAME;
00181 const int escape = !(flags & FNM_NOESCAPE);
00182 const int nocase = flags & FNM_CASEFOLD;
00183
00184 const char *ptmp = 0;
00185 const char *stmp = 0;
00186
00187 const char *p = *pcur;
00188 const char *pend = p + strlen(p);
00189 const char *s = *scur;
00190 const char *send = s + strlen(s);
00191
00192 int r;
00193
00194 if (period && *s == '.' && *UNESCAPE(p) != '.')
00195 RETURN(FNM_NOMATCH);
00196
00197 while (1) {
00198 switch (*p) {
00199 case '*':
00200 do { p++; } while (*p == '*');
00201 if (ISEND(UNESCAPE(p))) {
00202 p = UNESCAPE(p);
00203 RETURN(0);
00204 }
00205 if (ISEND(s))
00206 RETURN(FNM_NOMATCH);
00207 ptmp = p;
00208 stmp = s;
00209 continue;
00210
00211 case '?':
00212 if (ISEND(s))
00213 RETURN(FNM_NOMATCH);
00214 p++;
00215 Inc(s, send, enc);
00216 continue;
00217
00218 case '[': {
00219 const char *t;
00220 if (ISEND(s))
00221 RETURN(FNM_NOMATCH);
00222 if ((t = bracket(p + 1, pend, s, send, flags, enc)) != 0) {
00223 p = t;
00224 Inc(s, send, enc);
00225 continue;
00226 }
00227 goto failed;
00228 }
00229 }
00230
00231
00232 p = UNESCAPE(p);
00233 if (ISEND(s))
00234 RETURN(ISEND(p) ? 0 : FNM_NOMATCH);
00235 if (ISEND(p))
00236 goto failed;
00237 r = rb_enc_precise_mbclen(p, pend, enc);
00238 if (!MBCLEN_CHARFOUND_P(r))
00239 goto failed;
00240 if (r <= (send-s) && memcmp(p, s, r) == 0) {
00241 p += r;
00242 s += r;
00243 continue;
00244 }
00245 if (!nocase) goto failed;
00246 if (rb_enc_toupper(rb_enc_codepoint(p, pend, enc), enc) !=
00247 rb_enc_toupper(rb_enc_codepoint(s, send, enc), enc))
00248 goto failed;
00249 p += r;
00250 Inc(s, send, enc);
00251 continue;
00252
00253 failed:
00254 if (ptmp && stmp) {
00255 p = ptmp;
00256 Inc(stmp, send, enc);
00257 s = stmp;
00258 continue;
00259 }
00260 RETURN(FNM_NOMATCH);
00261 }
00262 }
00263
00264 static int
00265 fnmatch(
00266 const char *pattern,
00267 rb_encoding *enc,
00268 const char *string,
00269 int flags)
00270 {
00271 const char *p = pattern;
00272 const char *s = string;
00273 const char *send = s + strlen(string);
00274 const int period = !(flags & FNM_DOTMATCH);
00275 const int pathname = flags & FNM_PATHNAME;
00276
00277 const char *ptmp = 0;
00278 const char *stmp = 0;
00279
00280 if (pathname) {
00281 while (1) {
00282 if (p[0] == '*' && p[1] == '*' && p[2] == '/') {
00283 do { p += 3; } while (p[0] == '*' && p[1] == '*' && p[2] == '/');
00284 ptmp = p;
00285 stmp = s;
00286 }
00287 if (fnmatch_helper(&p, &s, flags, enc) == 0) {
00288 while (*s && *s != '/') Inc(s, send, enc);
00289 if (*p && *s) {
00290 p++;
00291 s++;
00292 continue;
00293 }
00294 if (!*p && !*s)
00295 return 0;
00296 }
00297
00298 if (ptmp && stmp && !(period && *stmp == '.')) {
00299 while (*stmp && *stmp != '/') Inc(stmp, send, enc);
00300 if (*stmp) {
00301 p = ptmp;
00302 stmp++;
00303 s = stmp;
00304 continue;
00305 }
00306 }
00307 return FNM_NOMATCH;
00308 }
00309 }
00310 else
00311 return fnmatch_helper(&p, &s, flags, enc);
00312 }
00313
00314 VALUE rb_cDir;
00315
00316 struct dir_data {
00317 DIR *dir;
00318 VALUE path;
00319 rb_encoding *enc;
00320 };
00321
00322 static void
00323 dir_mark(void *ptr)
00324 {
00325 struct dir_data *dir = ptr;
00326 rb_gc_mark(dir->path);
00327 }
00328
00329 static void
00330 dir_free(void *ptr)
00331 {
00332 struct dir_data *dir = ptr;
00333 if (dir) {
00334 if (dir->dir) closedir(dir->dir);
00335 }
00336 xfree(dir);
00337 }
00338
00339 static size_t
00340 dir_memsize(const void *ptr)
00341 {
00342 return ptr ? sizeof(struct dir_data) : 0;
00343 }
00344
00345 static const rb_data_type_t dir_data_type = {
00346 "dir",
00347 dir_mark, dir_free, dir_memsize
00348 };
00349
00350 static VALUE dir_close(VALUE);
00351
00352 #define GlobPathValue(str, safe) \
00353 \
00354 (!RB_TYPE_P(str, T_STRING) ? \
00355 FilePathValue(str) : \
00356 (check_safe_glob(str, safe), \
00357 check_glob_encoding(str), (str)))
00358 #define check_safe_glob(str, safe) ((safe) ? rb_check_safe_obj(str) : (void)0)
00359 #define check_glob_encoding(str) rb_enc_check((str), rb_enc_from_encoding(rb_usascii_encoding()))
00360
00361 static VALUE
00362 dir_s_alloc(VALUE klass)
00363 {
00364 struct dir_data *dirp;
00365 VALUE obj = TypedData_Make_Struct(klass, struct dir_data, &dir_data_type, dirp);
00366
00367 dirp->dir = NULL;
00368 dirp->path = Qnil;
00369 dirp->enc = NULL;
00370
00371 return obj;
00372 }
00373
00374
00375
00376
00377
00378
00379
00380 static VALUE
00381 dir_initialize(int argc, VALUE *argv, VALUE dir)
00382 {
00383 struct dir_data *dp;
00384 rb_encoding *fsenc;
00385 VALUE dirname, opt;
00386 static VALUE sym_enc;
00387
00388 if (!sym_enc) {
00389 sym_enc = ID2SYM(rb_intern("encoding"));
00390 }
00391 fsenc = rb_filesystem_encoding();
00392
00393 rb_scan_args(argc, argv, "11", &dirname, &opt);
00394
00395 if (!NIL_P(opt)) {
00396 VALUE v, enc=Qnil;
00397 opt = rb_convert_type(opt, T_HASH, "Hash", "to_hash");
00398
00399 v = rb_hash_aref(opt, sym_enc);
00400 if (!NIL_P(v)) enc = v;
00401
00402 if (!NIL_P(enc)) {
00403 fsenc = rb_to_encoding(enc);
00404 }
00405 }
00406
00407 GlobPathValue(dirname, FALSE);
00408
00409 TypedData_Get_Struct(dir, struct dir_data, &dir_data_type, dp);
00410 if (dp->dir) closedir(dp->dir);
00411 dp->dir = NULL;
00412 dp->path = Qnil;
00413 dp->enc = fsenc;
00414 dp->dir = opendir(RSTRING_PTR(dirname));
00415 if (dp->dir == NULL) {
00416 if (errno == EMFILE || errno == ENFILE) {
00417 rb_gc();
00418 dp->dir = opendir(RSTRING_PTR(dirname));
00419 }
00420 if (dp->dir == NULL) {
00421 rb_sys_fail(RSTRING_PTR(dirname));
00422 }
00423 }
00424 dp->path = rb_str_dup_frozen(dirname);
00425
00426 return dir;
00427 }
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440 static VALUE
00441 dir_s_open(int argc, VALUE *argv, VALUE klass)
00442 {
00443 struct dir_data *dp;
00444 VALUE dir = TypedData_Make_Struct(klass, struct dir_data, &dir_data_type, dp);
00445
00446 dir_initialize(argc, argv, dir);
00447 if (rb_block_given_p()) {
00448 return rb_ensure(rb_yield, dir, dir_close, dir);
00449 }
00450
00451 return dir;
00452 }
00453
00454 static void
00455 dir_closed(void)
00456 {
00457 rb_raise(rb_eIOError, "closed directory");
00458 }
00459
00460 static struct dir_data *
00461 dir_check(VALUE dir)
00462 {
00463 struct dir_data *dirp;
00464 if (!OBJ_UNTRUSTED(dir) && rb_safe_level() >= 4)
00465 rb_raise(rb_eSecurityError, "Insecure: operation on trusted Dir");
00466 rb_check_frozen(dir);
00467 dirp = rb_check_typeddata(dir, &dir_data_type);
00468 if (!dirp->dir) dir_closed();
00469 return dirp;
00470 }
00471
00472 #define GetDIR(obj, dirp) (dirp = dir_check(obj))
00473
00474
00475
00476
00477
00478
00479
00480
00481 static VALUE
00482 dir_inspect(VALUE dir)
00483 {
00484 struct dir_data *dirp;
00485
00486 TypedData_Get_Struct(dir, struct dir_data, &dir_data_type, dirp);
00487 if (!NIL_P(dirp->path)) {
00488 const char *c = rb_obj_classname(dir);
00489 return rb_sprintf("#<%s:%s>", c, RSTRING_PTR(dirp->path));
00490 }
00491 return rb_funcall(dir, rb_intern("to_s"), 0, 0);
00492 }
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503 static VALUE
00504 dir_path(VALUE dir)
00505 {
00506 struct dir_data *dirp;
00507
00508 TypedData_Get_Struct(dir, struct dir_data, &dir_data_type, dirp);
00509 if (NIL_P(dirp->path)) return Qnil;
00510 return rb_str_dup(dirp->path);
00511 }
00512
00513 #if defined HAVE_READDIR_R
00514 # define READDIR(dir, enc, entry, dp) (readdir_r(dir, entry, &(dp)) == 0 && dp != 0)
00515 #elif defined _WIN32
00516 # define READDIR(dir, enc, entry, dp) ((dp = rb_w32_readdir_with_enc(dir, enc)) != 0)
00517 #else
00518 # define READDIR(dir, enc, entry, dp) ((dp = readdir(dir)) != 0)
00519 #endif
00520 #if defined HAVE_READDIR_R
00521 # define IF_HAVE_READDIR_R(something) something
00522 #else
00523 # define IF_HAVE_READDIR_R(something)
00524 #endif
00525
00526 #if defined SIZEOF_STRUCT_DIRENT_TOO_SMALL
00527 # include <limits.h>
00528 # define NAME_MAX_FOR_STRUCT_DIRENT 255
00529 # if defined NAME_MAX
00530 # if NAME_MAX_FOR_STRUCT_DIRENT < NAME_MAX
00531 # undef NAME_MAX_FOR_STRUCT_DIRENT
00532 # define NAME_MAX_FOR_STRUCT_DIRENT NAME_MAX
00533 # endif
00534 # endif
00535 # if defined _POSIX_NAME_MAX
00536 # if NAME_MAX_FOR_STRUCT_DIRENT < _POSIX_NAME_MAX
00537 # undef NAME_MAX_FOR_STRUCT_DIRENT
00538 # define NAME_MAX_FOR_STRUCT_DIRENT _POSIX_NAME_MAX
00539 # endif
00540 # endif
00541 # if defined _XOPEN_NAME_MAX
00542 # if NAME_MAX_FOR_STRUCT_DIRENT < _XOPEN_NAME_MAX
00543 # undef NAME_MAX_FOR_STRUCT_DIRENT
00544 # define NAME_MAX_FOR_STRUCT_DIRENT _XOPEN_NAME_MAX
00545 # endif
00546 # endif
00547 # define DEFINE_STRUCT_DIRENT \
00548 union { \
00549 struct dirent dirent; \
00550 char dummy[offsetof(struct dirent, d_name) + \
00551 NAME_MAX_FOR_STRUCT_DIRENT + 1]; \
00552 }
00553 # define STRUCT_DIRENT(entry) ((entry).dirent)
00554 #else
00555 # define DEFINE_STRUCT_DIRENT struct dirent
00556 # define STRUCT_DIRENT(entry) (entry)
00557 #endif
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571 static VALUE
00572 dir_read(VALUE dir)
00573 {
00574 struct dir_data *dirp;
00575 struct dirent *dp;
00576 IF_HAVE_READDIR_R(DEFINE_STRUCT_DIRENT entry);
00577
00578 GetDIR(dir, dirp);
00579 errno = 0;
00580 if (READDIR(dirp->dir, dirp->enc, &STRUCT_DIRENT(entry), dp)) {
00581 return rb_external_str_new_with_enc(dp->d_name, NAMLEN(dp), dirp->enc);
00582 }
00583 else if (errno == 0) {
00584 return Qnil;
00585 }
00586 else {
00587 rb_sys_fail(0);
00588 }
00589 return Qnil;
00590 }
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612 static VALUE
00613 dir_each(VALUE dir)
00614 {
00615 struct dir_data *dirp;
00616 struct dirent *dp;
00617 IF_HAVE_READDIR_R(DEFINE_STRUCT_DIRENT entry);
00618
00619 RETURN_ENUMERATOR(dir, 0, 0);
00620 GetDIR(dir, dirp);
00621 rewinddir(dirp->dir);
00622 while (READDIR(dirp->dir, dirp->enc, &STRUCT_DIRENT(entry), dp)) {
00623 rb_yield(rb_external_str_new_with_enc(dp->d_name, NAMLEN(dp), dirp->enc));
00624 if (dirp->dir == NULL) dir_closed();
00625 }
00626 return dir;
00627 }
00628
00629 #ifdef HAVE_TELLDIR
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643 static VALUE
00644 dir_tell(VALUE dir)
00645 {
00646 struct dir_data *dirp;
00647 long pos;
00648
00649 GetDIR(dir, dirp);
00650 pos = telldir(dirp->dir);
00651 return rb_int2inum(pos);
00652 }
00653 #else
00654 #define dir_tell rb_f_notimplement
00655 #endif
00656
00657 #ifdef HAVE_SEEKDIR
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672 static VALUE
00673 dir_seek(VALUE dir, VALUE pos)
00674 {
00675 struct dir_data *dirp;
00676 long p = NUM2LONG(pos);
00677
00678 GetDIR(dir, dirp);
00679 seekdir(dirp->dir, p);
00680 return dir;
00681 }
00682 #else
00683 #define dir_seek rb_f_notimplement
00684 #endif
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700 static VALUE
00701 dir_set_pos(VALUE dir, VALUE pos)
00702 {
00703 dir_seek(dir, pos);
00704 return pos;
00705 }
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718 static VALUE
00719 dir_rewind(VALUE dir)
00720 {
00721 struct dir_data *dirp;
00722
00723 if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(dir)) {
00724 rb_raise(rb_eSecurityError, "Insecure: can't close");
00725 }
00726 GetDIR(dir, dirp);
00727 rewinddir(dirp->dir);
00728 return dir;
00729 }
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741 static VALUE
00742 dir_close(VALUE dir)
00743 {
00744 struct dir_data *dirp;
00745
00746 GetDIR(dir, dirp);
00747 closedir(dirp->dir);
00748 dirp->dir = NULL;
00749
00750 return Qnil;
00751 }
00752
00753 static void
00754 dir_chdir(VALUE path)
00755 {
00756 path = rb_str_encode_ospath(path);
00757 if (chdir(RSTRING_PTR(path)) < 0)
00758 rb_sys_fail(RSTRING_PTR(path));
00759 }
00760
00761 static int chdir_blocking = 0;
00762 static VALUE chdir_thread = Qnil;
00763
00764 struct chdir_data {
00765 VALUE old_path, new_path;
00766 int done;
00767 };
00768
00769 static VALUE
00770 chdir_yield(struct chdir_data *args)
00771 {
00772 dir_chdir(args->new_path);
00773 args->done = TRUE;
00774 chdir_blocking++;
00775 if (chdir_thread == Qnil)
00776 chdir_thread = rb_thread_current();
00777 return rb_yield(args->new_path);
00778 }
00779
00780 static VALUE
00781 chdir_restore(struct chdir_data *args)
00782 {
00783 if (args->done) {
00784 chdir_blocking--;
00785 if (chdir_blocking == 0)
00786 chdir_thread = Qnil;
00787 dir_chdir(args->old_path);
00788 }
00789 return Qnil;
00790 }
00791
00792
00793
00794
00795
00796
00797
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 static VALUE
00832 dir_s_chdir(int argc, VALUE *argv, VALUE obj)
00833 {
00834 VALUE path = Qnil;
00835
00836 rb_secure(2);
00837 if (rb_scan_args(argc, argv, "01", &path) == 1) {
00838 FilePathValue(path);
00839 }
00840 else {
00841 const char *dist = getenv("HOME");
00842 if (!dist) {
00843 dist = getenv("LOGDIR");
00844 if (!dist) rb_raise(rb_eArgError, "HOME/LOGDIR not set");
00845 }
00846 path = rb_str_new2(dist);
00847 }
00848
00849 if (chdir_blocking > 0) {
00850 if (!rb_block_given_p() || rb_thread_current() != chdir_thread)
00851 rb_warn("conflicting chdir during another chdir block");
00852 }
00853
00854 if (rb_block_given_p()) {
00855 struct chdir_data args;
00856 char *cwd = my_getcwd();
00857
00858 args.old_path = rb_tainted_str_new2(cwd); xfree(cwd);
00859 args.new_path = path;
00860 args.done = FALSE;
00861 return rb_ensure(chdir_yield, (VALUE)&args, chdir_restore, (VALUE)&args);
00862 }
00863 dir_chdir(path);
00864
00865 return INT2FIX(0);
00866 }
00867
00868 VALUE
00869 rb_dir_getwd(void)
00870 {
00871 char *path;
00872 VALUE cwd;
00873
00874 rb_secure(4);
00875 path = my_getcwd();
00876 cwd = rb_tainted_str_new2(path);
00877 rb_enc_associate(cwd, rb_filesystem_encoding());
00878
00879 xfree(path);
00880 return cwd;
00881 }
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894 static VALUE
00895 dir_s_getwd(VALUE dir)
00896 {
00897 return rb_dir_getwd();
00898 }
00899
00900 static void
00901 check_dirname(volatile VALUE *dir)
00902 {
00903 char *path, *pend;
00904
00905 rb_secure(2);
00906 FilePathValue(*dir);
00907 path = RSTRING_PTR(*dir);
00908 if (path && *(pend = rb_path_end(rb_path_skip_prefix(path)))) {
00909 *dir = rb_str_new(path, pend - path);
00910 }
00911 }
00912
00913 #if defined(HAVE_CHROOT)
00914
00915
00916
00917
00918
00919
00920
00921
00922
00923 static VALUE
00924 dir_s_chroot(VALUE dir, VALUE path)
00925 {
00926 check_dirname(&path);
00927
00928 path = rb_str_encode_ospath(path);
00929 if (chroot(RSTRING_PTR(path)) == -1)
00930 rb_sys_fail(RSTRING_PTR(path));
00931
00932 return INT2FIX(0);
00933 }
00934 #else
00935 #define dir_s_chroot rb_f_notimplement
00936 #endif
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951 static VALUE
00952 dir_s_mkdir(int argc, VALUE *argv, VALUE obj)
00953 {
00954 VALUE path, vmode;
00955 int mode;
00956
00957 if (rb_scan_args(argc, argv, "11", &path, &vmode) == 2) {
00958 mode = NUM2INT(vmode);
00959 }
00960 else {
00961 mode = 0777;
00962 }
00963
00964 check_dirname(&path);
00965 path = rb_str_encode_ospath(path);
00966 if (mkdir(RSTRING_PTR(path), mode) == -1)
00967 rb_sys_fail(RSTRING_PTR(path));
00968
00969 return INT2FIX(0);
00970 }
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981 static VALUE
00982 dir_s_rmdir(VALUE obj, VALUE dir)
00983 {
00984 check_dirname(&dir);
00985 dir = rb_str_encode_ospath(dir);
00986 if (rmdir(RSTRING_PTR(dir)) < 0)
00987 rb_sys_fail(RSTRING_PTR(dir));
00988
00989 return INT2FIX(0);
00990 }
00991
00992 static VALUE
00993 sys_warning_1(VALUE mesg)
00994 {
00995 rb_sys_warning("%s", (const char *)mesg);
00996 return Qnil;
00997 }
00998
00999 #define GLOB_VERBOSE (1U << (sizeof(int) * CHAR_BIT - 1))
01000 #define sys_warning(val) \
01001 (void)((flags & GLOB_VERBOSE) && rb_protect(sys_warning_1, (VALUE)(val), 0))
01002
01003 #define GLOB_ALLOC(type) (type *)malloc(sizeof(type))
01004 #define GLOB_ALLOC_N(type, n) (type *)malloc(sizeof(type) * (n))
01005 #define GLOB_FREE(ptr) free(ptr)
01006 #define GLOB_JUMP_TAG(status) ((status == -1) ? rb_memerror() : rb_jump_tag(status))
01007
01008
01009
01010
01011
01012 #define to_be_ignored(e) ((e) == ENOENT || (e) == ENOTDIR)
01013
01014
01015 static int
01016 do_stat(const char *path, struct stat *pst, int flags)
01017
01018 {
01019 int ret = stat(path, pst);
01020 if (ret < 0 && !to_be_ignored(errno))
01021 sys_warning(path);
01022
01023 return ret;
01024 }
01025
01026 static int
01027 do_lstat(const char *path, struct stat *pst, int flags)
01028 {
01029 int ret = lstat(path, pst);
01030 if (ret < 0 && !to_be_ignored(errno))
01031 sys_warning(path);
01032
01033 return ret;
01034 }
01035
01036 static DIR *
01037 do_opendir(const char *path, int flags)
01038 {
01039 DIR *dirp = opendir(path);
01040 if (dirp == NULL && !to_be_ignored(errno))
01041 sys_warning(path);
01042
01043 return dirp;
01044 }
01045
01046
01047 static int
01048 has_magic(const char *p, const char *pend, int flags, rb_encoding *enc)
01049 {
01050 const int escape = !(flags & FNM_NOESCAPE);
01051 const int nocase = flags & FNM_CASEFOLD;
01052
01053 register char c;
01054
01055 while (p < pend && (c = *p++) != 0) {
01056 switch (c) {
01057 case '*':
01058 case '?':
01059 case '[':
01060 return 1;
01061
01062 case '\\':
01063 if (escape && !(c = *p++))
01064 return 0;
01065 continue;
01066
01067 default:
01068 if (!FNM_SYSCASE && ISALPHA(c) && nocase)
01069 return 1;
01070 }
01071
01072 p = Next(p-1, pend, enc);
01073 }
01074
01075 return 0;
01076 }
01077
01078
01079 static char *
01080 find_dirsep(const char *p, const char *pend, int flags, rb_encoding *enc)
01081 {
01082 const int escape = !(flags & FNM_NOESCAPE);
01083
01084 register char c;
01085 int open = 0;
01086
01087 while ((c = *p++) != 0) {
01088 switch (c) {
01089 case '[':
01090 open = 1;
01091 continue;
01092 case ']':
01093 open = 0;
01094 continue;
01095
01096 case '/':
01097 if (!open)
01098 return (char *)p-1;
01099 continue;
01100
01101 case '\\':
01102 if (escape && !(c = *p++))
01103 return (char *)p-1;
01104 continue;
01105 }
01106
01107 p = Next(p-1, pend, enc);
01108 }
01109
01110 return (char *)p-1;
01111 }
01112
01113
01114 static void
01115 remove_backslashes(char *p, rb_encoding *enc)
01116 {
01117 register const char *pend = p + strlen(p);
01118 char *t = p;
01119 char *s = p;
01120
01121 while (*p) {
01122 if (*p == '\\') {
01123 if (t != s)
01124 memmove(t, s, p - s);
01125 t += p - s;
01126 s = ++p;
01127 if (!*p) break;
01128 }
01129 Inc(p, pend, enc);
01130 }
01131
01132 while (*p++);
01133
01134 if (t != s)
01135 memmove(t, s, p - s);
01136 }
01137
01138
01139 enum glob_pattern_type { PLAIN, MAGICAL, RECURSIVE, MATCH_ALL, MATCH_DIR };
01140
01141 struct glob_pattern {
01142 char *str;
01143 enum glob_pattern_type type;
01144 struct glob_pattern *next;
01145 };
01146
01147 static void glob_free_pattern(struct glob_pattern *list);
01148
01149 static struct glob_pattern *
01150 glob_make_pattern(const char *p, const char *e, int flags, rb_encoding *enc)
01151 {
01152 struct glob_pattern *list, *tmp, **tail = &list;
01153 int dirsep = 0;
01154
01155 while (p < e && *p) {
01156 tmp = GLOB_ALLOC(struct glob_pattern);
01157 if (!tmp) goto error;
01158 if (p[0] == '*' && p[1] == '*' && p[2] == '/') {
01159
01160 do { p += 3; while (*p == '/') p++; } while (p[0] == '*' && p[1] == '*' && p[2] == '/');
01161 tmp->type = RECURSIVE;
01162 tmp->str = 0;
01163 dirsep = 1;
01164 }
01165 else {
01166 const char *m = find_dirsep(p, e, flags, enc);
01167 int magic = has_magic(p, m, flags, enc);
01168 char *buf;
01169
01170 if (!magic && *m) {
01171 const char *m2;
01172 while (!has_magic(m+1, m2 = find_dirsep(m+1, e, flags, enc), flags, enc) &&
01173 *m2) {
01174 m = m2;
01175 }
01176 }
01177 buf = GLOB_ALLOC_N(char, m-p+1);
01178 if (!buf) {
01179 GLOB_FREE(tmp);
01180 goto error;
01181 }
01182 memcpy(buf, p, m-p);
01183 buf[m-p] = '\0';
01184 tmp->type = magic ? MAGICAL : PLAIN;
01185 tmp->str = buf;
01186 if (*m) {
01187 dirsep = 1;
01188 p = m + 1;
01189 }
01190 else {
01191 dirsep = 0;
01192 p = m;
01193 }
01194 }
01195 *tail = tmp;
01196 tail = &tmp->next;
01197 }
01198
01199 tmp = GLOB_ALLOC(struct glob_pattern);
01200 if (!tmp) {
01201 error:
01202 *tail = 0;
01203 glob_free_pattern(list);
01204 return 0;
01205 }
01206 tmp->type = dirsep ? MATCH_DIR : MATCH_ALL;
01207 tmp->str = 0;
01208 *tail = tmp;
01209 tmp->next = 0;
01210
01211 return list;
01212 }
01213
01214 static void
01215 glob_free_pattern(struct glob_pattern *list)
01216 {
01217 while (list) {
01218 struct glob_pattern *tmp = list;
01219 list = list->next;
01220 if (tmp->str)
01221 GLOB_FREE(tmp->str);
01222 GLOB_FREE(tmp);
01223 }
01224 }
01225
01226 static char *
01227 join_path(const char *path, int dirsep, const char *name)
01228 {
01229 long len = strlen(path);
01230 long len2 = strlen(name)+(dirsep?1:0)+1;
01231 char *buf = GLOB_ALLOC_N(char, len+len2);
01232
01233 if (!buf) return 0;
01234 memcpy(buf, path, len);
01235 if (dirsep) {
01236 buf[len++] = '/';
01237 }
01238 buf[len] = '\0';
01239 strlcat(buf+len, name, len2);
01240 return buf;
01241 }
01242
01243 enum answer { YES, NO, UNKNOWN };
01244
01245 #ifndef S_ISDIR
01246 # define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR)
01247 #endif
01248
01249 #ifndef S_ISLNK
01250 # ifndef S_IFLNK
01251 # define S_ISLNK(m) (0)
01252 # else
01253 # define S_ISLNK(m) ((m & S_IFMT) == S_IFLNK)
01254 # endif
01255 #endif
01256
01257 struct glob_args {
01258 void (*func)(const char *, VALUE, void *);
01259 const char *path;
01260 VALUE value;
01261 rb_encoding *enc;
01262 };
01263
01264 static VALUE
01265 glob_func_caller(VALUE val)
01266 {
01267 struct glob_args *args = (struct glob_args *)val;
01268
01269 (*args->func)(args->path, args->value, args->enc);
01270 return Qnil;
01271 }
01272
01273 #define glob_call_func(func, path, arg, enc) (*func)(path, arg, enc)
01274
01275 static int
01276 glob_helper(
01277 const char *path,
01278 int dirsep,
01279 enum answer exist,
01280 enum answer isdir,
01281 struct glob_pattern **beg,
01282 struct glob_pattern **end,
01283 int flags,
01284 ruby_glob_func *func,
01285 VALUE arg,
01286 rb_encoding *enc)
01287 {
01288 struct stat st;
01289 int status = 0;
01290 struct glob_pattern **cur, **new_beg, **new_end;
01291 int plain = 0, magical = 0, recursive = 0, match_all = 0, match_dir = 0;
01292 int escape = !(flags & FNM_NOESCAPE);
01293
01294 for (cur = beg; cur < end; ++cur) {
01295 struct glob_pattern *p = *cur;
01296 if (p->type == RECURSIVE) {
01297 recursive = 1;
01298 p = p->next;
01299 }
01300 switch (p->type) {
01301 case PLAIN:
01302 plain = 1;
01303 break;
01304 case MAGICAL:
01305 magical = 1;
01306 break;
01307 case MATCH_ALL:
01308 match_all = 1;
01309 break;
01310 case MATCH_DIR:
01311 match_dir = 1;
01312 break;
01313 case RECURSIVE:
01314 rb_bug("continuous RECURSIVEs");
01315 }
01316 }
01317
01318 if (*path) {
01319 if (match_all && exist == UNKNOWN) {
01320 if (do_lstat(path, &st, flags) == 0) {
01321 exist = YES;
01322 isdir = S_ISDIR(st.st_mode) ? YES : S_ISLNK(st.st_mode) ? UNKNOWN : NO;
01323 }
01324 else {
01325 exist = NO;
01326 isdir = NO;
01327 }
01328 }
01329 if (match_dir && isdir == UNKNOWN) {
01330 if (do_stat(path, &st, flags) == 0) {
01331 exist = YES;
01332 isdir = S_ISDIR(st.st_mode) ? YES : NO;
01333 }
01334 else {
01335 exist = NO;
01336 isdir = NO;
01337 }
01338 }
01339 if (match_all && exist == YES) {
01340 status = glob_call_func(func, path, arg, enc);
01341 if (status) return status;
01342 }
01343 if (match_dir && isdir == YES) {
01344 char *tmp = join_path(path, dirsep, "");
01345 if (!tmp) return -1;
01346 status = glob_call_func(func, tmp, arg, enc);
01347 GLOB_FREE(tmp);
01348 if (status) return status;
01349 }
01350 }
01351
01352 if (exist == NO || isdir == NO) return 0;
01353
01354 if (magical || recursive) {
01355 struct dirent *dp;
01356 DIR *dirp;
01357 IF_HAVE_READDIR_R(DEFINE_STRUCT_DIRENT entry);
01358 dirp = do_opendir(*path ? path : ".", flags);
01359 if (dirp == NULL) return 0;
01360
01361 while (READDIR(dirp, enc, &STRUCT_DIRENT(entry), dp)) {
01362 char *buf = join_path(path, dirsep, dp->d_name);
01363 enum answer new_isdir = UNKNOWN;
01364
01365 if (!buf) {
01366 status = -1;
01367 break;
01368 }
01369 if (recursive && strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0
01370 && fnmatch("*", rb_usascii_encoding(), dp->d_name, flags) == 0) {
01371 #ifndef _WIN32
01372 if (do_lstat(buf, &st, flags) == 0)
01373 new_isdir = S_ISDIR(st.st_mode) ? YES : S_ISLNK(st.st_mode) ? UNKNOWN : NO;
01374 else
01375 new_isdir = NO;
01376 #else
01377 new_isdir = dp->d_isdir ? (!dp->d_isrep ? YES : UNKNOWN) : NO;
01378 #endif
01379 }
01380
01381 new_beg = new_end = GLOB_ALLOC_N(struct glob_pattern *, (end - beg) * 2);
01382 if (!new_beg) {
01383 GLOB_FREE(buf);
01384 status = -1;
01385 break;
01386 }
01387
01388 for (cur = beg; cur < end; ++cur) {
01389 struct glob_pattern *p = *cur;
01390 if (p->type == RECURSIVE) {
01391 if (new_isdir == YES)
01392 *new_end++ = p;
01393 p = p->next;
01394 }
01395 if (p->type == PLAIN || p->type == MAGICAL) {
01396 if (fnmatch(p->str, enc, dp->d_name, flags) == 0)
01397 *new_end++ = p->next;
01398 }
01399 }
01400
01401 status = glob_helper(buf, 1, YES, new_isdir, new_beg, new_end,
01402 flags, func, arg, enc);
01403 GLOB_FREE(buf);
01404 GLOB_FREE(new_beg);
01405 if (status) break;
01406 }
01407
01408 closedir(dirp);
01409 }
01410 else if (plain) {
01411 struct glob_pattern **copy_beg, **copy_end, **cur2;
01412
01413 copy_beg = copy_end = GLOB_ALLOC_N(struct glob_pattern *, end - beg);
01414 if (!copy_beg) return -1;
01415 for (cur = beg; cur < end; ++cur)
01416 *copy_end++ = (*cur)->type == PLAIN ? *cur : 0;
01417
01418 for (cur = copy_beg; cur < copy_end; ++cur) {
01419 if (*cur) {
01420 char *buf;
01421 char *name;
01422 size_t len = strlen((*cur)->str) + 1;
01423 name = GLOB_ALLOC_N(char, len);
01424 if (!name) {
01425 status = -1;
01426 break;
01427 }
01428 memcpy(name, (*cur)->str, len);
01429 if (escape) remove_backslashes(name, enc);
01430
01431 new_beg = new_end = GLOB_ALLOC_N(struct glob_pattern *, end - beg);
01432 if (!new_beg) {
01433 GLOB_FREE(name);
01434 status = -1;
01435 break;
01436 }
01437 *new_end++ = (*cur)->next;
01438 for (cur2 = cur + 1; cur2 < copy_end; ++cur2) {
01439 if (*cur2 && fnmatch((*cur2)->str, enc, name, flags) == 0) {
01440 *new_end++ = (*cur2)->next;
01441 *cur2 = 0;
01442 }
01443 }
01444
01445 buf = join_path(path, dirsep, name);
01446 GLOB_FREE(name);
01447 if (!buf) {
01448 GLOB_FREE(new_beg);
01449 status = -1;
01450 break;
01451 }
01452 status = glob_helper(buf, 1, UNKNOWN, UNKNOWN, new_beg,
01453 new_end, flags, func, arg, enc);
01454 GLOB_FREE(buf);
01455 GLOB_FREE(new_beg);
01456 if (status) break;
01457 }
01458 }
01459
01460 GLOB_FREE(copy_beg);
01461 }
01462
01463 return status;
01464 }
01465
01466 static int
01467 ruby_glob0(const char *path, int flags, ruby_glob_func *func, VALUE arg, rb_encoding *enc)
01468 {
01469 struct glob_pattern *list;
01470 const char *root, *start;
01471 char *buf;
01472 size_t n;
01473 int status;
01474
01475 start = root = path;
01476 flags |= FNM_SYSCASE;
01477 #if defined DOSISH
01478 root = rb_path_skip_prefix(root);
01479 #endif
01480
01481 if (root && *root == '/') root++;
01482
01483 n = root - start;
01484 buf = GLOB_ALLOC_N(char, n + 1);
01485 if (!buf) return -1;
01486 MEMCPY(buf, start, char, n);
01487 buf[n] = '\0';
01488
01489 list = glob_make_pattern(root, root + strlen(root), flags, enc);
01490 if (!list) {
01491 GLOB_FREE(buf);
01492 return -1;
01493 }
01494 status = glob_helper(buf, 0, UNKNOWN, UNKNOWN, &list, &list + 1, flags, func, arg, enc);
01495 glob_free_pattern(list);
01496 GLOB_FREE(buf);
01497
01498 return status;
01499 }
01500
01501 int
01502 ruby_glob(const char *path, int flags, ruby_glob_func *func, VALUE arg)
01503 {
01504 return ruby_glob0(path, flags & ~GLOB_VERBOSE, func, arg,
01505 rb_ascii8bit_encoding());
01506 }
01507
01508 static int
01509 rb_glob_caller(const char *path, VALUE a, void *enc)
01510 {
01511 int status;
01512 struct glob_args *args = (struct glob_args *)a;
01513
01514 args->path = path;
01515 rb_protect(glob_func_caller, a, &status);
01516 return status;
01517 }
01518
01519 static int
01520 rb_glob2(const char *path, int flags,
01521 void (*func)(const char *, VALUE, void *), VALUE arg,
01522 rb_encoding* enc)
01523 {
01524 struct glob_args args;
01525
01526 args.func = func;
01527 args.value = arg;
01528 args.enc = enc;
01529
01530 if (flags & FNM_SYSCASE) {
01531 rb_warning("Dir.glob() ignores File::FNM_CASEFOLD");
01532 }
01533
01534 return ruby_glob0(path, flags | GLOB_VERBOSE, rb_glob_caller, (VALUE)&args,
01535 enc);
01536 }
01537
01538 void
01539 rb_glob(const char *path, void (*func)(const char *, VALUE, void *), VALUE arg)
01540 {
01541 int status = rb_glob2(path, 0, func, arg, rb_ascii8bit_encoding());
01542 if (status) GLOB_JUMP_TAG(status);
01543 }
01544
01545 static void
01546 push_pattern(const char *path, VALUE ary, void *enc)
01547 {
01548 rb_ary_push(ary, rb_external_str_new_with_enc(path, strlen(path), enc));
01549 }
01550
01551 static int
01552 ruby_brace_expand(const char *str, int flags, ruby_glob_func *func, VALUE arg,
01553 rb_encoding *enc)
01554 {
01555 const int escape = !(flags & FNM_NOESCAPE);
01556 const char *p = str;
01557 const char *pend = p + strlen(p);
01558 const char *s = p;
01559 const char *lbrace = 0, *rbrace = 0;
01560 int nest = 0, status = 0;
01561
01562 while (*p) {
01563 if (*p == '{' && nest++ == 0) {
01564 lbrace = p;
01565 }
01566 if (*p == '}' && --nest <= 0) {
01567 rbrace = p;
01568 break;
01569 }
01570 if (*p == '\\' && escape) {
01571 if (!*++p) break;
01572 }
01573 Inc(p, pend, enc);
01574 }
01575
01576 if (lbrace && rbrace) {
01577 size_t len = strlen(s) + 1;
01578 char *buf = GLOB_ALLOC_N(char, len);
01579 long shift;
01580
01581 if (!buf) return -1;
01582 memcpy(buf, s, lbrace-s);
01583 shift = (lbrace-s);
01584 p = lbrace;
01585 while (p < rbrace) {
01586 const char *t = ++p;
01587 nest = 0;
01588 while (p < rbrace && !(*p == ',' && nest == 0)) {
01589 if (*p == '{') nest++;
01590 if (*p == '}') nest--;
01591 if (*p == '\\' && escape) {
01592 if (++p == rbrace) break;
01593 }
01594 Inc(p, pend, enc);
01595 }
01596 memcpy(buf+shift, t, p-t);
01597 strlcpy(buf+shift+(p-t), rbrace+1, len-(shift+(p-t)));
01598 status = ruby_brace_expand(buf, flags, func, arg, enc);
01599 if (status) break;
01600 }
01601 GLOB_FREE(buf);
01602 }
01603 else if (!lbrace && !rbrace) {
01604 status = (*func)(s, arg, enc);
01605 }
01606
01607 return status;
01608 }
01609
01610 struct brace_args {
01611 ruby_glob_func *func;
01612 VALUE value;
01613 int flags;
01614 };
01615
01616 static int
01617 glob_brace(const char *path, VALUE val, void *enc)
01618 {
01619 struct brace_args *arg = (struct brace_args *)val;
01620
01621 return ruby_glob0(path, arg->flags, arg->func, arg->value, enc);
01622 }
01623
01624 static int
01625 ruby_brace_glob0(const char *str, int flags, ruby_glob_func *func, VALUE arg,
01626 rb_encoding* enc)
01627 {
01628 struct brace_args args;
01629
01630 args.func = func;
01631 args.value = arg;
01632 args.flags = flags;
01633 return ruby_brace_expand(str, flags, glob_brace, (VALUE)&args, enc);
01634 }
01635
01636 int
01637 ruby_brace_glob(const char *str, int flags, ruby_glob_func *func, VALUE arg)
01638 {
01639 return ruby_brace_glob0(str, flags & ~GLOB_VERBOSE, func, arg,
01640 rb_ascii8bit_encoding());
01641 }
01642
01643 int
01644 ruby_brace_glob_with_enc(const char *str, int flags, ruby_glob_func *func, VALUE arg, rb_encoding *enc)
01645 {
01646 return ruby_brace_glob0(str, flags & ~GLOB_VERBOSE, func, arg, enc);
01647 }
01648
01649 static int
01650 push_glob(VALUE ary, VALUE str, int flags)
01651 {
01652 struct glob_args args;
01653 rb_encoding *enc = rb_enc_get(str);
01654
01655 if (enc == rb_usascii_encoding()) enc = rb_filesystem_encoding();
01656 args.func = push_pattern;
01657 args.value = ary;
01658 args.enc = enc;
01659
01660 RB_GC_GUARD(str);
01661 return ruby_brace_glob0(RSTRING_PTR(str), flags | GLOB_VERBOSE,
01662 rb_glob_caller, (VALUE)&args, enc);
01663 }
01664
01665 static VALUE
01666 rb_push_glob(VALUE str, int flags)
01667 {
01668 long offset = 0;
01669 VALUE ary;
01670
01671 GlobPathValue(str, TRUE);
01672 ary = rb_ary_new();
01673
01674 while (offset < RSTRING_LEN(str)) {
01675 char *p, *pend;
01676 int status;
01677 p = RSTRING_PTR(str) + offset;
01678 status = push_glob(ary, rb_enc_str_new(p, strlen(p), rb_enc_get(str)),
01679 flags);
01680 if (status) GLOB_JUMP_TAG(status);
01681 if (offset >= RSTRING_LEN(str)) break;
01682 p += strlen(p) + 1;
01683 pend = RSTRING_PTR(str) + RSTRING_LEN(str);
01684 while (p < pend && !*p)
01685 p++;
01686 offset = p - RSTRING_PTR(str);
01687 }
01688
01689 return ary;
01690 }
01691
01692 static VALUE
01693 dir_globs(long argc, VALUE *argv, int flags)
01694 {
01695 VALUE ary = rb_ary_new();
01696 long i;
01697
01698 for (i = 0; i < argc; ++i) {
01699 int status;
01700 VALUE str = argv[i];
01701 GlobPathValue(str, TRUE);
01702 status = push_glob(ary, str, flags);
01703 if (status) GLOB_JUMP_TAG(status);
01704 }
01705
01706 return ary;
01707 }
01708
01709
01710
01711
01712
01713
01714
01715
01716
01717
01718
01719 static VALUE
01720 dir_s_aref(int argc, VALUE *argv, VALUE obj)
01721 {
01722 if (argc == 1) {
01723 return rb_push_glob(argv[0], 0);
01724 }
01725 return dir_globs(argc, argv, 0);
01726 }
01727
01728
01729
01730
01731
01732
01733
01734
01735
01736
01737
01738
01739
01740
01741
01742
01743
01744
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 static VALUE
01795 dir_s_glob(int argc, VALUE *argv, VALUE obj)
01796 {
01797 VALUE str, rflags, ary;
01798 int flags;
01799
01800 if (rb_scan_args(argc, argv, "11", &str, &rflags) == 2)
01801 flags = NUM2INT(rflags);
01802 else
01803 flags = 0;
01804
01805 ary = rb_check_array_type(str);
01806 if (NIL_P(ary)) {
01807 ary = rb_push_glob(str, flags);
01808 }
01809 else {
01810 volatile VALUE v = ary;
01811 ary = dir_globs(RARRAY_LEN(v), RARRAY_PTR(v), flags);
01812 }
01813
01814 if (rb_block_given_p()) {
01815 rb_ary_each(ary);
01816 return Qnil;
01817 }
01818 return ary;
01819 }
01820
01821 static VALUE
01822 dir_open_dir(int argc, VALUE *argv)
01823 {
01824 VALUE dir = rb_funcall2(rb_cDir, rb_intern("open"), argc, argv);
01825 struct dir_data *dirp;
01826
01827 TypedData_Get_Struct(dir, struct dir_data, &dir_data_type, dirp);
01828 return dir;
01829 }
01830
01831
01832
01833
01834
01835
01836
01837
01838
01839
01840
01841
01842
01843
01844
01845
01846
01847
01848
01849
01850
01851
01852 static VALUE
01853 dir_foreach(int argc, VALUE *argv, VALUE io)
01854 {
01855 VALUE dir;
01856
01857 RETURN_ENUMERATOR(io, argc, argv);
01858 dir = dir_open_dir(argc, argv);
01859 rb_ensure(dir_each, dir, dir_close, dir);
01860 return Qnil;
01861 }
01862
01863
01864
01865
01866
01867
01868
01869
01870
01871
01872
01873
01874 static VALUE
01875 dir_entries(int argc, VALUE *argv, VALUE io)
01876 {
01877 VALUE dir;
01878
01879 dir = dir_open_dir(argc, argv);
01880 return rb_ensure(rb_Array, dir, dir_close, dir);
01881 }
01882
01883
01884
01885
01886
01887
01888
01889
01890
01891
01892
01893
01894
01895
01896
01897
01898
01899
01900
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 static VALUE
01965 file_s_fnmatch(int argc, VALUE *argv, VALUE obj)
01966 {
01967 VALUE pattern, path;
01968 VALUE rflags;
01969 int flags;
01970
01971 if (rb_scan_args(argc, argv, "21", &pattern, &path, &rflags) == 3)
01972 flags = NUM2INT(rflags);
01973 else
01974 flags = 0;
01975
01976 StringValue(pattern);
01977 FilePathStringValue(path);
01978
01979 if (fnmatch(RSTRING_PTR(pattern), rb_enc_get(pattern), RSTRING_PTR(path),
01980 flags) == 0)
01981 return Qtrue;
01982
01983 return Qfalse;
01984 }
01985
01986 VALUE rb_home_dir(const char *user, VALUE result);
01987
01988
01989
01990
01991
01992
01993
01994
01995
01996 static VALUE
01997 dir_s_home(int argc, VALUE *argv, VALUE obj)
01998 {
01999 VALUE user;
02000 const char *u = 0;
02001
02002 rb_scan_args(argc, argv, "01", &user);
02003 if (!NIL_P(user)) {
02004 SafeStringValue(user);
02005 u = StringValueCStr(user);
02006 }
02007 return rb_home_dir(u, rb_str_new(0, 0));
02008 }
02009
02010
02011
02012
02013
02014
02015
02016
02017
02018
02019
02020
02021 void
02022 Init_Dir(void)
02023 {
02024 rb_cDir = rb_define_class("Dir", rb_cObject);
02025
02026 rb_include_module(rb_cDir, rb_mEnumerable);
02027
02028 rb_define_alloc_func(rb_cDir, dir_s_alloc);
02029 rb_define_singleton_method(rb_cDir, "open", dir_s_open, -1);
02030 rb_define_singleton_method(rb_cDir, "foreach", dir_foreach, -1);
02031 rb_define_singleton_method(rb_cDir, "entries", dir_entries, -1);
02032
02033 rb_define_method(rb_cDir,"initialize", dir_initialize, -1);
02034 rb_define_method(rb_cDir,"path", dir_path, 0);
02035 rb_define_method(rb_cDir,"to_path", dir_path, 0);
02036 rb_define_method(rb_cDir,"inspect", dir_inspect, 0);
02037 rb_define_method(rb_cDir,"read", dir_read, 0);
02038 rb_define_method(rb_cDir,"each", dir_each, 0);
02039 rb_define_method(rb_cDir,"rewind", dir_rewind, 0);
02040 rb_define_method(rb_cDir,"tell", dir_tell, 0);
02041 rb_define_method(rb_cDir,"seek", dir_seek, 1);
02042 rb_define_method(rb_cDir,"pos", dir_tell, 0);
02043 rb_define_method(rb_cDir,"pos=", dir_set_pos, 1);
02044 rb_define_method(rb_cDir,"close", dir_close, 0);
02045
02046 rb_define_singleton_method(rb_cDir,"chdir", dir_s_chdir, -1);
02047 rb_define_singleton_method(rb_cDir,"getwd", dir_s_getwd, 0);
02048 rb_define_singleton_method(rb_cDir,"pwd", dir_s_getwd, 0);
02049 rb_define_singleton_method(rb_cDir,"chroot", dir_s_chroot, 1);
02050 rb_define_singleton_method(rb_cDir,"mkdir", dir_s_mkdir, -1);
02051 rb_define_singleton_method(rb_cDir,"rmdir", dir_s_rmdir, 1);
02052 rb_define_singleton_method(rb_cDir,"delete", dir_s_rmdir, 1);
02053 rb_define_singleton_method(rb_cDir,"unlink", dir_s_rmdir, 1);
02054 rb_define_singleton_method(rb_cDir,"home", dir_s_home, -1);
02055
02056 rb_define_singleton_method(rb_cDir,"glob", dir_s_glob, -1);
02057 rb_define_singleton_method(rb_cDir,"[]", dir_s_aref, -1);
02058 rb_define_singleton_method(rb_cDir,"exist?", rb_file_directory_p, 1);
02059 rb_define_singleton_method(rb_cDir,"exists?", rb_file_directory_p, 1);
02060
02061 rb_define_singleton_method(rb_cFile,"fnmatch", file_s_fnmatch, -1);
02062 rb_define_singleton_method(rb_cFile,"fnmatch?", file_s_fnmatch, -1);
02063
02064 rb_file_const("FNM_NOESCAPE", INT2FIX(FNM_NOESCAPE));
02065 rb_file_const("FNM_PATHNAME", INT2FIX(FNM_PATHNAME));
02066 rb_file_const("FNM_DOTMATCH", INT2FIX(FNM_DOTMATCH));
02067 rb_file_const("FNM_CASEFOLD", INT2FIX(FNM_CASEFOLD));
02068 rb_file_const("FNM_SYSCASE", INT2FIX(FNM_SYSCASE));
02069 }
02070