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