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 # define NAMLEN(dirent) (dirent)->d_namlen
00034 # if HAVE_SYS_NDIR_H
00035 # include <sys/ndir.h>
00036 # endif
00037 # if HAVE_SYS_DIR_H
00038 # include <sys/dir.h>
00039 # endif
00040 # if HAVE_NDIR_H
00041 # include <ndir.h>
00042 # endif
00043 # ifdef _WIN32
00044 # include "win32/dir.h"
00045 # endif
00046 #endif
00047 #if defined(__native_client__) && defined(NACL_NEWLIB)
00048 # include "nacl/dirent.h"
00049 # include "nacl/stat.h"
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 #undef opendir
00079 #define opendir(p) rb_w32_uopendir(p)
00080 #endif
00081
00082 #define rb_sys_fail_path(path) rb_sys_fail_str(path)
00083
00084 #define FNM_NOESCAPE 0x01
00085 #define FNM_PATHNAME 0x02
00086 #define FNM_DOTMATCH 0x04
00087 #define FNM_CASEFOLD 0x08
00088 #define FNM_EXTGLOB 0x10
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, r2) == 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 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((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 {
00593 if (errno != 0) rb_sys_fail(0);
00594 return Qnil;
00595 }
00596 }
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618 static VALUE
00619 dir_each(VALUE dir)
00620 {
00621 struct dir_data *dirp;
00622 struct dirent *dp;
00623 IF_HAVE_READDIR_R(DEFINE_STRUCT_DIRENT entry);
00624
00625 RETURN_ENUMERATOR(dir, 0, 0);
00626 GetDIR(dir, dirp);
00627 rewinddir(dirp->dir);
00628 while (READDIR(dirp->dir, dirp->enc, &STRUCT_DIRENT(entry), dp)) {
00629 rb_yield(rb_external_str_new_with_enc(dp->d_name, NAMLEN(dp), dirp->enc));
00630 if (dirp->dir == NULL) dir_closed();
00631 }
00632 return dir;
00633 }
00634
00635 #ifdef HAVE_TELLDIR
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649 static VALUE
00650 dir_tell(VALUE dir)
00651 {
00652 struct dir_data *dirp;
00653 long pos;
00654
00655 GetDIR(dir, dirp);
00656 pos = telldir(dirp->dir);
00657 return rb_int2inum(pos);
00658 }
00659 #else
00660 #define dir_tell rb_f_notimplement
00661 #endif
00662
00663 #ifdef HAVE_SEEKDIR
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678 static VALUE
00679 dir_seek(VALUE dir, VALUE pos)
00680 {
00681 struct dir_data *dirp;
00682 long p = NUM2LONG(pos);
00683
00684 GetDIR(dir, dirp);
00685 seekdir(dirp->dir, p);
00686 return dir;
00687 }
00688 #else
00689 #define dir_seek rb_f_notimplement
00690 #endif
00691
00692 #ifdef HAVE_SEEKDIR
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707 static VALUE
00708 dir_set_pos(VALUE dir, VALUE pos)
00709 {
00710 dir_seek(dir, pos);
00711 return pos;
00712 }
00713 #else
00714 #define dir_set_pos rb_f_notimplement
00715 #endif
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728 static VALUE
00729 dir_rewind(VALUE dir)
00730 {
00731 struct dir_data *dirp;
00732
00733 if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(dir)) {
00734 rb_raise(rb_eSecurityError, "Insecure: can't close");
00735 }
00736 GetDIR(dir, dirp);
00737 rewinddir(dirp->dir);
00738 return dir;
00739 }
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751 static VALUE
00752 dir_close(VALUE dir)
00753 {
00754 struct dir_data *dirp;
00755
00756 GetDIR(dir, dirp);
00757 closedir(dirp->dir);
00758 dirp->dir = NULL;
00759
00760 return Qnil;
00761 }
00762
00763 static void
00764 dir_chdir(VALUE path)
00765 {
00766 if (chdir(RSTRING_PTR(path)) < 0)
00767 rb_sys_fail_path(path);
00768 }
00769
00770 static int chdir_blocking = 0;
00771 static VALUE chdir_thread = Qnil;
00772
00773 struct chdir_data {
00774 VALUE old_path, new_path;
00775 int done;
00776 };
00777
00778 static VALUE
00779 chdir_yield(struct chdir_data *args)
00780 {
00781 dir_chdir(args->new_path);
00782 args->done = TRUE;
00783 chdir_blocking++;
00784 if (chdir_thread == Qnil)
00785 chdir_thread = rb_thread_current();
00786 return rb_yield(args->new_path);
00787 }
00788
00789 static VALUE
00790 chdir_restore(struct chdir_data *args)
00791 {
00792 if (args->done) {
00793 chdir_blocking--;
00794 if (chdir_blocking == 0)
00795 chdir_thread = Qnil;
00796 dir_chdir(args->old_path);
00797 }
00798 return Qnil;
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
00840 static VALUE
00841 dir_s_chdir(int argc, VALUE *argv, VALUE obj)
00842 {
00843 VALUE path = Qnil;
00844
00845 rb_secure(2);
00846 if (rb_scan_args(argc, argv, "01", &path) == 1) {
00847 FilePathValue(path);
00848 path = rb_str_encode_ospath(path);
00849 }
00850 else {
00851 const char *dist = getenv("HOME");
00852 if (!dist) {
00853 dist = getenv("LOGDIR");
00854 if (!dist) rb_raise(rb_eArgError, "HOME/LOGDIR not set");
00855 }
00856 path = rb_str_new2(dist);
00857 }
00858
00859 if (chdir_blocking > 0) {
00860 if (!rb_block_given_p() || rb_thread_current() != chdir_thread)
00861 rb_warn("conflicting chdir during another chdir block");
00862 }
00863
00864 if (rb_block_given_p()) {
00865 struct chdir_data args;
00866
00867 args.old_path = rb_str_encode_ospath(rb_dir_getwd());
00868 args.new_path = path;
00869 args.done = FALSE;
00870 return rb_ensure(chdir_yield, (VALUE)&args, chdir_restore, (VALUE)&args);
00871 }
00872 dir_chdir(path);
00873
00874 return INT2FIX(0);
00875 }
00876
00877 VALUE
00878 rb_dir_getwd(void)
00879 {
00880 char *path;
00881 VALUE cwd;
00882
00883 rb_secure(4);
00884 path = my_getcwd();
00885 cwd = rb_tainted_str_new2(path);
00886 rb_enc_associate(cwd, rb_filesystem_encoding());
00887
00888 xfree(path);
00889 return cwd;
00890 }
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903 static VALUE
00904 dir_s_getwd(VALUE dir)
00905 {
00906 return rb_dir_getwd();
00907 }
00908
00909 static void
00910 check_dirname(volatile VALUE *dir)
00911 {
00912 VALUE d = *dir;
00913 char *path, *pend;
00914 long len;
00915 rb_encoding *enc;
00916
00917 rb_secure(2);
00918 FilePathValue(d);
00919 enc = rb_enc_get(d);
00920 RSTRING_GETMEM(d, path, len);
00921 pend = path + len;
00922 pend = rb_enc_path_end(rb_enc_path_skip_prefix(path, pend, enc), pend, enc);
00923 if (pend - path < len) {
00924 d = rb_str_subseq(d, 0, pend - path);
00925 }
00926 *dir = rb_str_encode_ospath(d);
00927 }
00928
00929 #if defined(HAVE_CHROOT)
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939 static VALUE
00940 dir_s_chroot(VALUE dir, VALUE path)
00941 {
00942 check_dirname(&path);
00943 if (chroot(RSTRING_PTR(path)) == -1)
00944 rb_sys_fail_path(path);
00945
00946 return INT2FIX(0);
00947 }
00948 #else
00949 #define dir_s_chroot rb_f_notimplement
00950 #endif
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965
00966
00967 static VALUE
00968 dir_s_mkdir(int argc, VALUE *argv, VALUE obj)
00969 {
00970 VALUE path, vmode;
00971 int mode;
00972
00973 if (rb_scan_args(argc, argv, "11", &path, &vmode) == 2) {
00974 mode = NUM2INT(vmode);
00975 }
00976 else {
00977 mode = 0777;
00978 }
00979
00980 check_dirname(&path);
00981 if (mkdir(RSTRING_PTR(path), mode) == -1)
00982 rb_sys_fail_path(path);
00983
00984 return INT2FIX(0);
00985 }
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996 static VALUE
00997 dir_s_rmdir(VALUE obj, VALUE dir)
00998 {
00999 check_dirname(&dir);
01000 if (rmdir(RSTRING_PTR(dir)) < 0)
01001 rb_sys_fail_path(dir);
01002
01003 return INT2FIX(0);
01004 }
01005
01006 static VALUE
01007 sys_warning_1(VALUE mesg)
01008 {
01009 rb_sys_warning("%s:%s", strerror(errno), (const char *)mesg);
01010 return Qnil;
01011 }
01012
01013 #define GLOB_VERBOSE (1U << (sizeof(int) * CHAR_BIT - 1))
01014 #define sys_warning(val) \
01015 (void)((flags & GLOB_VERBOSE) && rb_protect(sys_warning_1, (VALUE)(val), 0))
01016
01017 #define GLOB_ALLOC(type) ((type *)malloc(sizeof(type)))
01018 #define GLOB_ALLOC_N(type, n) ((type *)malloc(sizeof(type) * (n)))
01019 #define GLOB_FREE(ptr) free(ptr)
01020 #define GLOB_JUMP_TAG(status) (((status) == -1) ? rb_memerror() : rb_jump_tag(status))
01021
01022
01023
01024
01025
01026 #define to_be_ignored(e) ((e) == ENOENT || (e) == ENOTDIR)
01027
01028
01029 static int
01030 do_stat(const char *path, struct stat *pst, int flags)
01031
01032 {
01033 int ret = stat(path, pst);
01034 if (ret < 0 && !to_be_ignored(errno))
01035 sys_warning(path);
01036
01037 return ret;
01038 }
01039
01040 static int
01041 do_lstat(const char *path, struct stat *pst, int flags)
01042 {
01043 int ret = lstat(path, pst);
01044 if (ret < 0 && !to_be_ignored(errno))
01045 sys_warning(path);
01046
01047 return ret;
01048 }
01049
01050 static DIR *
01051 do_opendir(const char *path, int flags, rb_encoding *enc)
01052 {
01053 DIR *dirp;
01054 #ifdef _WIN32
01055 volatile VALUE tmp;
01056 if (enc != rb_usascii_encoding() &&
01057 enc != rb_ascii8bit_encoding() &&
01058 enc != rb_utf8_encoding()) {
01059 tmp = rb_enc_str_new(path, strlen(path), enc);
01060 tmp = rb_str_encode_ospath(tmp);
01061 path = RSTRING_PTR(tmp);
01062 }
01063 #endif
01064 dirp = opendir(path);
01065 if (dirp == NULL && !to_be_ignored(errno))
01066 sys_warning(path);
01067
01068 return dirp;
01069 }
01070
01071
01072 static int
01073 has_magic(const char *p, const char *pend, int flags, rb_encoding *enc)
01074 {
01075 const int escape = !(flags & FNM_NOESCAPE);
01076 const int nocase = flags & FNM_CASEFOLD;
01077
01078 register char c;
01079
01080 while (p < pend && (c = *p++) != 0) {
01081 switch (c) {
01082 case '*':
01083 case '?':
01084 case '[':
01085 return 1;
01086
01087 case '\\':
01088 if (escape && !(c = *p++))
01089 return 0;
01090 continue;
01091
01092 default:
01093 if (!FNM_SYSCASE && ISALPHA(c) && nocase)
01094 return 1;
01095 }
01096
01097 p = Next(p-1, pend, enc);
01098 }
01099
01100 return 0;
01101 }
01102
01103
01104 static char *
01105 find_dirsep(const char *p, const char *pend, int flags, rb_encoding *enc)
01106 {
01107 const int escape = !(flags & FNM_NOESCAPE);
01108
01109 register char c;
01110 int open = 0;
01111
01112 while ((c = *p++) != 0) {
01113 switch (c) {
01114 case '[':
01115 open = 1;
01116 continue;
01117 case ']':
01118 open = 0;
01119 continue;
01120
01121 case '/':
01122 if (!open)
01123 return (char *)p-1;
01124 continue;
01125
01126 case '\\':
01127 if (escape && !(c = *p++))
01128 return (char *)p-1;
01129 continue;
01130 }
01131
01132 p = Next(p-1, pend, enc);
01133 }
01134
01135 return (char *)p-1;
01136 }
01137
01138
01139 static char *
01140 remove_backslashes(char *p, register const char *pend, rb_encoding *enc)
01141 {
01142 char *t = p;
01143 char *s = p;
01144
01145 while (*p) {
01146 if (*p == '\\') {
01147 if (t != s)
01148 memmove(t, s, p - s);
01149 t += p - s;
01150 s = ++p;
01151 if (!*p) break;
01152 }
01153 Inc(p, pend, enc);
01154 }
01155
01156 while (*p++);
01157
01158 if (t != s)
01159 memmove(t, s, p - s);
01160
01161 return p;
01162 }
01163
01164
01165 enum glob_pattern_type { PLAIN, MAGICAL, RECURSIVE, MATCH_ALL, MATCH_DIR };
01166
01167 struct glob_pattern {
01168 char *str;
01169 enum glob_pattern_type type;
01170 struct glob_pattern *next;
01171 };
01172
01173 static void glob_free_pattern(struct glob_pattern *list);
01174
01175 static struct glob_pattern *
01176 glob_make_pattern(const char *p, const char *e, int flags, rb_encoding *enc)
01177 {
01178 struct glob_pattern *list, *tmp, **tail = &list;
01179 int dirsep = 0;
01180 int recursive = 0;
01181
01182 while (p < e && *p) {
01183 tmp = GLOB_ALLOC(struct glob_pattern);
01184 if (!tmp) goto error;
01185 if (p[0] == '*' && p[1] == '*' && p[2] == '/') {
01186
01187 do { p += 3; while (*p == '/') p++; } while (p[0] == '*' && p[1] == '*' && p[2] == '/');
01188 tmp->type = RECURSIVE;
01189 tmp->str = 0;
01190 dirsep = 1;
01191 recursive = 1;
01192 }
01193 else {
01194 const char *m = find_dirsep(p, e, flags, enc);
01195 int magic = has_magic(p, m, flags, enc);
01196 char *buf;
01197
01198 if (!magic && !recursive && *m) {
01199 const char *m2;
01200 while (!has_magic(m+1, m2 = find_dirsep(m+1, e, flags, enc), flags, enc) &&
01201 *m2) {
01202 m = m2;
01203 }
01204 }
01205 buf = GLOB_ALLOC_N(char, m-p+1);
01206 if (!buf) {
01207 GLOB_FREE(tmp);
01208 goto error;
01209 }
01210 memcpy(buf, p, m-p);
01211 buf[m-p] = '\0';
01212 tmp->type = magic ? MAGICAL : PLAIN;
01213 tmp->str = buf;
01214 if (*m) {
01215 dirsep = 1;
01216 p = m + 1;
01217 }
01218 else {
01219 dirsep = 0;
01220 p = m;
01221 }
01222 }
01223 *tail = tmp;
01224 tail = &tmp->next;
01225 }
01226
01227 tmp = GLOB_ALLOC(struct glob_pattern);
01228 if (!tmp) {
01229 error:
01230 *tail = 0;
01231 glob_free_pattern(list);
01232 return 0;
01233 }
01234 tmp->type = dirsep ? MATCH_DIR : MATCH_ALL;
01235 tmp->str = 0;
01236 *tail = tmp;
01237 tmp->next = 0;
01238
01239 return list;
01240 }
01241
01242 static void
01243 glob_free_pattern(struct glob_pattern *list)
01244 {
01245 while (list) {
01246 struct glob_pattern *tmp = list;
01247 list = list->next;
01248 if (tmp->str)
01249 GLOB_FREE(tmp->str);
01250 GLOB_FREE(tmp);
01251 }
01252 }
01253
01254 static char *
01255 join_path(const char *path, int dirsep, const char *name, size_t namlen)
01256 {
01257 long len = strlen(path);
01258 char *buf = GLOB_ALLOC_N(char, len+namlen+(dirsep?1:0)+1);
01259
01260 if (!buf) return 0;
01261 memcpy(buf, path, len);
01262 if (dirsep) {
01263 buf[len++] = '/';
01264 }
01265 memcpy(buf+len, name, namlen);
01266 buf[len+namlen] = '\0';
01267 return buf;
01268 }
01269
01270 enum answer {UNKNOWN = -1, NO, YES};
01271
01272 #ifndef S_ISDIR
01273 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
01274 #endif
01275
01276 #ifndef S_ISLNK
01277 # ifndef S_IFLNK
01278 # define S_ISLNK(m) (0)
01279 # else
01280 # define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
01281 # endif
01282 #endif
01283
01284 struct glob_args {
01285 void (*func)(const char *, VALUE, void *);
01286 const char *path;
01287 VALUE value;
01288 rb_encoding *enc;
01289 };
01290
01291 static VALUE
01292 glob_func_caller(VALUE val)
01293 {
01294 struct glob_args *args = (struct glob_args *)val;
01295
01296 (*args->func)(args->path, args->value, args->enc);
01297 return Qnil;
01298 }
01299
01300 #define glob_call_func(func, path, arg, enc) (*(func))((path), (arg), (enc))
01301
01302 static int
01303 glob_helper(
01304 const char *path,
01305 int dirsep,
01306 enum answer exist,
01307 enum answer isdir,
01308 struct glob_pattern **beg,
01309 struct glob_pattern **end,
01310 int flags,
01311 ruby_glob_func *func,
01312 VALUE arg,
01313 rb_encoding *enc)
01314 {
01315 struct stat st;
01316 int status = 0;
01317 struct glob_pattern **cur, **new_beg, **new_end;
01318 int plain = 0, magical = 0, recursive = 0, match_all = 0, match_dir = 0;
01319 int escape = !(flags & FNM_NOESCAPE);
01320
01321 for (cur = beg; cur < end; ++cur) {
01322 struct glob_pattern *p = *cur;
01323 if (p->type == RECURSIVE) {
01324 recursive = 1;
01325 p = p->next;
01326 }
01327 switch (p->type) {
01328 case PLAIN:
01329 plain = 1;
01330 break;
01331 case MAGICAL:
01332 magical = 1;
01333 break;
01334 case MATCH_ALL:
01335 match_all = 1;
01336 break;
01337 case MATCH_DIR:
01338 match_dir = 1;
01339 break;
01340 case RECURSIVE:
01341 rb_bug("continuous RECURSIVEs");
01342 }
01343 }
01344
01345 if (*path) {
01346 if (match_all && exist == UNKNOWN) {
01347 if (do_lstat(path, &st, flags) == 0) {
01348 exist = YES;
01349 isdir = S_ISDIR(st.st_mode) ? YES : S_ISLNK(st.st_mode) ? UNKNOWN : NO;
01350 }
01351 else {
01352 exist = NO;
01353 isdir = NO;
01354 }
01355 }
01356 if (match_dir && isdir == UNKNOWN) {
01357 if (do_stat(path, &st, flags) == 0) {
01358 exist = YES;
01359 isdir = S_ISDIR(st.st_mode) ? YES : NO;
01360 }
01361 else {
01362 exist = NO;
01363 isdir = NO;
01364 }
01365 }
01366 if (match_all && exist == YES) {
01367 status = glob_call_func(func, path, arg, enc);
01368 if (status) return status;
01369 }
01370 if (match_dir && isdir == YES) {
01371 char *tmp = join_path(path, dirsep, "", 0);
01372 if (!tmp) return -1;
01373 status = glob_call_func(func, tmp, arg, enc);
01374 GLOB_FREE(tmp);
01375 if (status) return status;
01376 }
01377 }
01378
01379 if (exist == NO || isdir == NO) return 0;
01380
01381 if (magical || recursive) {
01382 struct dirent *dp;
01383 DIR *dirp;
01384 IF_HAVE_READDIR_R(DEFINE_STRUCT_DIRENT entry);
01385 dirp = do_opendir(*path ? path : ".", flags, enc);
01386 if (dirp == NULL) return 0;
01387
01388 while (READDIR(dirp, enc, &STRUCT_DIRENT(entry), dp)) {
01389 char *buf;
01390 enum answer new_isdir = UNKNOWN;
01391 int dotfile = 0;
01392
01393 if (recursive && dp->d_name[0] == '.') {
01394 ++dotfile;
01395 if (!dp->d_name[1]) {
01396
01397 if (!(flags & FNM_DOTMATCH)) continue;
01398 ++dotfile;
01399 }
01400 else if (dp->d_name[1] == '.' && !dp->d_name[2]) {
01401
01402 continue;
01403 }
01404 }
01405
01406 buf = join_path(path, dirsep, dp->d_name, NAMLEN(dp));
01407 if (!buf) {
01408 status = -1;
01409 break;
01410 }
01411 if (recursive && dotfile < ((flags & FNM_DOTMATCH) ? 2 : 1)) {
01412
01413 #ifndef _WIN32
01414 if (do_lstat(buf, &st, flags) == 0)
01415 new_isdir = S_ISDIR(st.st_mode) ? YES : S_ISLNK(st.st_mode) ? UNKNOWN : NO;
01416 else
01417 new_isdir = NO;
01418 #else
01419 new_isdir = dp->d_isdir ? (!dp->d_isrep ? YES : UNKNOWN) : NO;
01420 #endif
01421 }
01422
01423 new_beg = new_end = GLOB_ALLOC_N(struct glob_pattern *, (end - beg) * 2);
01424 if (!new_beg) {
01425 GLOB_FREE(buf);
01426 status = -1;
01427 break;
01428 }
01429
01430 for (cur = beg; cur < end; ++cur) {
01431 struct glob_pattern *p = *cur;
01432 if (p->type == RECURSIVE) {
01433 if (new_isdir == YES)
01434 *new_end++ = p;
01435 p = p->next;
01436 }
01437 if (p->type == PLAIN || p->type == MAGICAL) {
01438 if (fnmatch(p->str, enc, dp->d_name, flags) == 0)
01439 *new_end++ = p->next;
01440 }
01441 }
01442
01443 status = glob_helper(buf, 1, YES, new_isdir, new_beg, new_end,
01444 flags, func, arg, enc);
01445 GLOB_FREE(buf);
01446 GLOB_FREE(new_beg);
01447 if (status) break;
01448 }
01449
01450 closedir(dirp);
01451 }
01452 else if (plain) {
01453 struct glob_pattern **copy_beg, **copy_end, **cur2;
01454
01455 copy_beg = copy_end = GLOB_ALLOC_N(struct glob_pattern *, end - beg);
01456 if (!copy_beg) return -1;
01457 for (cur = beg; cur < end; ++cur)
01458 *copy_end++ = (*cur)->type == PLAIN ? *cur : 0;
01459
01460 for (cur = copy_beg; cur < copy_end; ++cur) {
01461 if (*cur) {
01462 char *buf;
01463 char *name;
01464 size_t len = strlen((*cur)->str) + 1;
01465 name = GLOB_ALLOC_N(char, len);
01466 if (!name) {
01467 status = -1;
01468 break;
01469 }
01470 memcpy(name, (*cur)->str, len);
01471 if (escape)
01472 len = remove_backslashes(name, name+len-1, enc) - name;
01473
01474 new_beg = new_end = GLOB_ALLOC_N(struct glob_pattern *, end - beg);
01475 if (!new_beg) {
01476 GLOB_FREE(name);
01477 status = -1;
01478 break;
01479 }
01480 *new_end++ = (*cur)->next;
01481 for (cur2 = cur + 1; cur2 < copy_end; ++cur2) {
01482 if (*cur2 && fnmatch((*cur2)->str, enc, name, flags) == 0) {
01483 *new_end++ = (*cur2)->next;
01484 *cur2 = 0;
01485 }
01486 }
01487
01488 buf = join_path(path, dirsep, name, len);
01489 GLOB_FREE(name);
01490 if (!buf) {
01491 GLOB_FREE(new_beg);
01492 status = -1;
01493 break;
01494 }
01495 status = glob_helper(buf, 1, UNKNOWN, UNKNOWN, new_beg,
01496 new_end, flags, func, arg, enc);
01497 GLOB_FREE(buf);
01498 GLOB_FREE(new_beg);
01499 if (status) break;
01500 }
01501 }
01502
01503 GLOB_FREE(copy_beg);
01504 }
01505
01506 return status;
01507 }
01508
01509 static int
01510 ruby_glob0(const char *path, int flags, ruby_glob_func *func, VALUE arg, rb_encoding *enc)
01511 {
01512 struct glob_pattern *list;
01513 const char *root, *start;
01514 char *buf;
01515 size_t n;
01516 int status;
01517
01518 start = root = path;
01519 flags |= FNM_SYSCASE;
01520 #if defined DOSISH
01521 root = rb_enc_path_skip_prefix(root, root + strlen(root), enc);
01522 #endif
01523
01524 if (root && *root == '/') root++;
01525
01526 n = root - start;
01527 buf = GLOB_ALLOC_N(char, n + 1);
01528 if (!buf) return -1;
01529 MEMCPY(buf, start, char, n);
01530 buf[n] = '\0';
01531
01532 list = glob_make_pattern(root, root + strlen(root), flags, enc);
01533 if (!list) {
01534 GLOB_FREE(buf);
01535 return -1;
01536 }
01537 status = glob_helper(buf, 0, UNKNOWN, UNKNOWN, &list, &list + 1, flags, func, arg, enc);
01538 glob_free_pattern(list);
01539 GLOB_FREE(buf);
01540
01541 return status;
01542 }
01543
01544 int
01545 ruby_glob(const char *path, int flags, ruby_glob_func *func, VALUE arg)
01546 {
01547 return ruby_glob0(path, flags & ~GLOB_VERBOSE, func, arg,
01548 rb_ascii8bit_encoding());
01549 }
01550
01551 static int
01552 rb_glob_caller(const char *path, VALUE a, void *enc)
01553 {
01554 int status;
01555 struct glob_args *args = (struct glob_args *)a;
01556
01557 args->path = path;
01558 rb_protect(glob_func_caller, a, &status);
01559 return status;
01560 }
01561
01562 static int
01563 rb_glob2(const char *path, int flags,
01564 void (*func)(const char *, VALUE, void *), VALUE arg,
01565 rb_encoding* enc)
01566 {
01567 struct glob_args args;
01568
01569 args.func = func;
01570 args.value = arg;
01571 args.enc = enc;
01572
01573 if (flags & FNM_SYSCASE) {
01574 rb_warning("Dir.glob() ignores File::FNM_CASEFOLD");
01575 }
01576
01577 return ruby_glob0(path, flags | GLOB_VERBOSE, rb_glob_caller, (VALUE)&args,
01578 enc);
01579 }
01580
01581 void
01582 rb_glob(const char *path, void (*func)(const char *, VALUE, void *), VALUE arg)
01583 {
01584 int status = rb_glob2(path, 0, func, arg, rb_ascii8bit_encoding());
01585 if (status) GLOB_JUMP_TAG(status);
01586 }
01587
01588 static void
01589 push_pattern(const char *path, VALUE ary, void *enc)
01590 {
01591 rb_ary_push(ary, rb_external_str_new_with_enc(path, strlen(path), enc));
01592 }
01593
01594 static int
01595 ruby_brace_expand(const char *str, int flags, ruby_glob_func *func, VALUE arg,
01596 rb_encoding *enc)
01597 {
01598 const int escape = !(flags & FNM_NOESCAPE);
01599 const char *p = str;
01600 const char *pend = p + strlen(p);
01601 const char *s = p;
01602 const char *lbrace = 0, *rbrace = 0;
01603 int nest = 0, status = 0;
01604
01605 while (*p) {
01606 if (*p == '{' && nest++ == 0) {
01607 lbrace = p;
01608 }
01609 if (*p == '}' && --nest <= 0) {
01610 rbrace = p;
01611 break;
01612 }
01613 if (*p == '\\' && escape) {
01614 if (!*++p) break;
01615 }
01616 Inc(p, pend, enc);
01617 }
01618
01619 if (lbrace && rbrace) {
01620 size_t len = strlen(s) + 1;
01621 char *buf = GLOB_ALLOC_N(char, len);
01622 long shift;
01623
01624 if (!buf) return -1;
01625 memcpy(buf, s, lbrace-s);
01626 shift = (lbrace-s);
01627 p = lbrace;
01628 while (p < rbrace) {
01629 const char *t = ++p;
01630 nest = 0;
01631 while (p < rbrace && !(*p == ',' && nest == 0)) {
01632 if (*p == '{') nest++;
01633 if (*p == '}') nest--;
01634 if (*p == '\\' && escape) {
01635 if (++p == rbrace) break;
01636 }
01637 Inc(p, pend, enc);
01638 }
01639 memcpy(buf+shift, t, p-t);
01640 strlcpy(buf+shift+(p-t), rbrace+1, len-(shift+(p-t)));
01641 status = ruby_brace_expand(buf, flags, func, arg, enc);
01642 if (status) break;
01643 }
01644 GLOB_FREE(buf);
01645 }
01646 else if (!lbrace && !rbrace) {
01647 status = (*func)(s, arg, enc);
01648 }
01649
01650 return status;
01651 }
01652
01653 struct brace_args {
01654 ruby_glob_func *func;
01655 VALUE value;
01656 int flags;
01657 };
01658
01659 static int
01660 glob_brace(const char *path, VALUE val, void *enc)
01661 {
01662 struct brace_args *arg = (struct brace_args *)val;
01663
01664 return ruby_glob0(path, arg->flags, arg->func, arg->value, enc);
01665 }
01666
01667 static int
01668 ruby_brace_glob0(const char *str, int flags, ruby_glob_func *func, VALUE arg,
01669 rb_encoding* enc)
01670 {
01671 struct brace_args args;
01672
01673 args.func = func;
01674 args.value = arg;
01675 args.flags = flags;
01676 return ruby_brace_expand(str, flags, glob_brace, (VALUE)&args, enc);
01677 }
01678
01679 int
01680 ruby_brace_glob(const char *str, int flags, ruby_glob_func *func, VALUE arg)
01681 {
01682 return ruby_brace_glob0(str, flags & ~GLOB_VERBOSE, func, arg,
01683 rb_ascii8bit_encoding());
01684 }
01685
01686 int
01687 ruby_brace_glob_with_enc(const char *str, int flags, ruby_glob_func *func, VALUE arg, rb_encoding *enc)
01688 {
01689 return ruby_brace_glob0(str, flags & ~GLOB_VERBOSE, func, arg, enc);
01690 }
01691
01692 static int
01693 push_glob(VALUE ary, VALUE str, int flags)
01694 {
01695 struct glob_args args;
01696 rb_encoding *enc = rb_enc_get(str);
01697
01698 if (enc == rb_usascii_encoding()) enc = rb_filesystem_encoding();
01699 args.func = push_pattern;
01700 args.value = ary;
01701 args.enc = enc;
01702
01703 RB_GC_GUARD(str);
01704 return ruby_brace_glob0(RSTRING_PTR(str), flags | GLOB_VERBOSE,
01705 rb_glob_caller, (VALUE)&args, enc);
01706 }
01707
01708 static VALUE
01709 rb_push_glob(VALUE str, int flags)
01710 {
01711 long offset = 0;
01712 VALUE ary;
01713
01714 GlobPathValue(str, TRUE);
01715 ary = rb_ary_new();
01716
01717 while (offset < RSTRING_LEN(str)) {
01718 char *p, *pend;
01719 int status;
01720 p = RSTRING_PTR(str) + offset;
01721 status = push_glob(ary, rb_enc_str_new(p, strlen(p), rb_enc_get(str)),
01722 flags);
01723 if (status) GLOB_JUMP_TAG(status);
01724 if (offset >= RSTRING_LEN(str)) break;
01725 p += strlen(p) + 1;
01726 pend = RSTRING_PTR(str) + RSTRING_LEN(str);
01727 while (p < pend && !*p)
01728 p++;
01729 offset = p - RSTRING_PTR(str);
01730 }
01731
01732 return ary;
01733 }
01734
01735 static VALUE
01736 dir_globs(long argc, VALUE *argv, int flags)
01737 {
01738 VALUE ary = rb_ary_new();
01739 long i;
01740
01741 for (i = 0; i < argc; ++i) {
01742 int status;
01743 VALUE str = argv[i];
01744 GlobPathValue(str, TRUE);
01745 status = push_glob(ary, str, flags);
01746 if (status) GLOB_JUMP_TAG(status);
01747 }
01748
01749 return ary;
01750 }
01751
01752
01753
01754
01755
01756
01757
01758
01759
01760 static VALUE
01761 dir_s_aref(int argc, VALUE *argv, VALUE obj)
01762 {
01763 if (argc == 1) {
01764 return rb_push_glob(argv[0], 0);
01765 }
01766 return dir_globs(argc, argv, 0);
01767 }
01768
01769
01770
01771
01772
01773
01774
01775
01776
01777
01778
01779
01780
01781
01782
01783
01784
01785
01786
01787
01788
01789
01790
01791
01792
01793
01794
01795
01796
01797
01798
01799
01800
01801
01802
01803
01804
01805
01806
01807
01808
01809
01810
01811
01812
01813
01814
01815
01816
01817
01818
01819
01820
01821
01822
01823
01824
01825
01826
01827
01828
01829
01830
01831
01832
01833
01834
01835
01836
01837 static VALUE
01838 dir_s_glob(int argc, VALUE *argv, VALUE obj)
01839 {
01840 VALUE str, rflags, ary;
01841 int flags;
01842
01843 if (rb_scan_args(argc, argv, "11", &str, &rflags) == 2)
01844 flags = NUM2INT(rflags);
01845 else
01846 flags = 0;
01847
01848 ary = rb_check_array_type(str);
01849 if (NIL_P(ary)) {
01850 ary = rb_push_glob(str, flags);
01851 }
01852 else {
01853 volatile VALUE v = ary;
01854 ary = dir_globs(RARRAY_LEN(v), RARRAY_PTR(v), flags);
01855 }
01856
01857 if (rb_block_given_p()) {
01858 rb_ary_each(ary);
01859 return Qnil;
01860 }
01861 return ary;
01862 }
01863
01864 static VALUE
01865 dir_open_dir(int argc, VALUE *argv)
01866 {
01867 VALUE dir = rb_funcall2(rb_cDir, rb_intern("open"), argc, argv);
01868
01869 rb_check_typeddata(dir, &dir_data_type);
01870 return dir;
01871 }
01872
01873
01874
01875
01876
01877
01878
01879
01880
01881
01882
01883
01884
01885
01886
01887
01888
01889
01890
01891
01892
01893
01894 static VALUE
01895 dir_foreach(int argc, VALUE *argv, VALUE io)
01896 {
01897 VALUE dir;
01898
01899 RETURN_ENUMERATOR(io, argc, argv);
01900 dir = dir_open_dir(argc, argv);
01901 rb_ensure(dir_each, dir, dir_close, dir);
01902 return Qnil;
01903 }
01904
01905
01906
01907
01908
01909
01910
01911
01912
01913
01914
01915
01916 static VALUE
01917 dir_entries(int argc, VALUE *argv, VALUE io)
01918 {
01919 VALUE dir;
01920
01921 dir = dir_open_dir(argc, argv);
01922 return rb_ensure(rb_Array, dir, dir_close, dir);
01923 }
01924
01925 static int
01926 fnmatch_brace(const char *pattern, VALUE val, void *enc)
01927 {
01928 struct brace_args *arg = (struct brace_args *)val;
01929 VALUE path = arg->value;
01930 rb_encoding *enc_pattern = enc;
01931 rb_encoding *enc_path = rb_enc_get(path);
01932
01933 if (enc_pattern != enc_path) {
01934 if (!rb_enc_asciicompat(enc_pattern))
01935 return FNM_NOMATCH;
01936 if (!rb_enc_asciicompat(enc_path))
01937 return FNM_NOMATCH;
01938 if (!rb_enc_str_asciionly_p(path)) {
01939 int cr = ENC_CODERANGE_7BIT;
01940 long len = strlen(pattern);
01941 if (rb_str_coderange_scan_restartable(pattern, pattern + len,
01942 enc_pattern, &cr) != len)
01943 return FNM_NOMATCH;
01944 if (cr != ENC_CODERANGE_7BIT)
01945 return FNM_NOMATCH;
01946 }
01947 }
01948 return (fnmatch(pattern, enc, RSTRING_PTR(path), arg->flags) == 0);
01949 }
01950
01951
01952
01953
01954
01955
01956
01957
01958
01959
01960
01961
01962
01963
01964
01965
01966
01967
01968
01969
01970
01971
01972
01973
01974
01975
01976
01977
01978
01979
01980
01981
01982
01983
01984
01985
01986
01987
01988
01989
01990
01991
01992
01993
01994
01995
01996
01997
01998
01999
02000
02001
02002
02003
02004
02005
02006
02007
02008
02009
02010
02011
02012
02013
02014
02015
02016
02017
02018
02019
02020
02021
02022
02023
02024
02025
02026
02027
02028
02029
02030
02031
02032 static VALUE
02033 file_s_fnmatch(int argc, VALUE *argv, VALUE obj)
02034 {
02035 VALUE pattern, path;
02036 VALUE rflags;
02037 int flags;
02038
02039 if (rb_scan_args(argc, argv, "21", &pattern, &path, &rflags) == 3)
02040 flags = NUM2INT(rflags);
02041 else
02042 flags = 0;
02043
02044 StringValue(pattern);
02045 FilePathStringValue(path);
02046
02047 if (flags & FNM_EXTGLOB) {
02048 struct brace_args args;
02049
02050 args.value = path;
02051 args.flags = flags;
02052 if (ruby_brace_expand(RSTRING_PTR(pattern), flags, fnmatch_brace,
02053 (VALUE)&args, rb_enc_get(pattern)) > 0)
02054 return Qtrue;
02055 }
02056 else {
02057 rb_encoding *enc = rb_enc_compatible(pattern, path);
02058 if (!enc) return Qfalse;
02059 if (fnmatch(RSTRING_PTR(pattern), enc, RSTRING_PTR(path), flags) == 0)
02060 return Qtrue;
02061 }
02062 RB_GC_GUARD(pattern);
02063
02064 return Qfalse;
02065 }
02066
02067
02068
02069
02070
02071
02072
02073
02074
02075 static VALUE
02076 dir_s_home(int argc, VALUE *argv, VALUE obj)
02077 {
02078 VALUE user;
02079 const char *u = 0;
02080
02081 rb_scan_args(argc, argv, "01", &user);
02082 if (!NIL_P(user)) {
02083 SafeStringValue(user);
02084 u = StringValueCStr(user);
02085 }
02086 return rb_home_dir(u, rb_str_new(0, 0));
02087 }
02088
02089 #if 0
02090
02091
02092
02093
02094
02095
02096
02097
02098
02099 VALUE
02100 rb_file_directory_p()
02101 {
02102 }
02103 #endif
02104
02105
02106
02107
02108
02109
02110
02111
02112
02113
02114
02115
02116 void
02117 Init_Dir(void)
02118 {
02119 rb_cDir = rb_define_class("Dir", rb_cObject);
02120
02121 rb_include_module(rb_cDir, rb_mEnumerable);
02122
02123 rb_define_alloc_func(rb_cDir, dir_s_alloc);
02124 rb_define_singleton_method(rb_cDir, "open", dir_s_open, -1);
02125 rb_define_singleton_method(rb_cDir, "foreach", dir_foreach, -1);
02126 rb_define_singleton_method(rb_cDir, "entries", dir_entries, -1);
02127
02128 rb_define_method(rb_cDir,"initialize", dir_initialize, -1);
02129 rb_define_method(rb_cDir,"path", dir_path, 0);
02130 rb_define_method(rb_cDir,"to_path", dir_path, 0);
02131 rb_define_method(rb_cDir,"inspect", dir_inspect, 0);
02132 rb_define_method(rb_cDir,"read", dir_read, 0);
02133 rb_define_method(rb_cDir,"each", dir_each, 0);
02134 rb_define_method(rb_cDir,"rewind", dir_rewind, 0);
02135 rb_define_method(rb_cDir,"tell", dir_tell, 0);
02136 rb_define_method(rb_cDir,"seek", dir_seek, 1);
02137 rb_define_method(rb_cDir,"pos", dir_tell, 0);
02138 rb_define_method(rb_cDir,"pos=", dir_set_pos, 1);
02139 rb_define_method(rb_cDir,"close", dir_close, 0);
02140
02141 rb_define_singleton_method(rb_cDir,"chdir", dir_s_chdir, -1);
02142 rb_define_singleton_method(rb_cDir,"getwd", dir_s_getwd, 0);
02143 rb_define_singleton_method(rb_cDir,"pwd", dir_s_getwd, 0);
02144 rb_define_singleton_method(rb_cDir,"chroot", dir_s_chroot, 1);
02145 rb_define_singleton_method(rb_cDir,"mkdir", dir_s_mkdir, -1);
02146 rb_define_singleton_method(rb_cDir,"rmdir", dir_s_rmdir, 1);
02147 rb_define_singleton_method(rb_cDir,"delete", dir_s_rmdir, 1);
02148 rb_define_singleton_method(rb_cDir,"unlink", dir_s_rmdir, 1);
02149 rb_define_singleton_method(rb_cDir,"home", dir_s_home, -1);
02150
02151 rb_define_singleton_method(rb_cDir,"glob", dir_s_glob, -1);
02152 rb_define_singleton_method(rb_cDir,"[]", dir_s_aref, -1);
02153 rb_define_singleton_method(rb_cDir,"exist?", rb_file_directory_p, 1);
02154 rb_define_singleton_method(rb_cDir,"exists?", rb_file_directory_p, 1);
02155
02156 rb_define_singleton_method(rb_cFile,"fnmatch", file_s_fnmatch, -1);
02157 rb_define_singleton_method(rb_cFile,"fnmatch?", file_s_fnmatch, -1);
02158
02159 rb_file_const("FNM_NOESCAPE", INT2FIX(FNM_NOESCAPE));
02160 rb_file_const("FNM_PATHNAME", INT2FIX(FNM_PATHNAME));
02161 rb_file_const("FNM_DOTMATCH", INT2FIX(FNM_DOTMATCH));
02162 rb_file_const("FNM_CASEFOLD", INT2FIX(FNM_CASEFOLD));
02163 rb_file_const("FNM_EXTGLOB", INT2FIX(FNM_EXTGLOB));
02164 rb_file_const("FNM_SYSCASE", INT2FIX(FNM_SYSCASE));
02165 }
02166