00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "ruby.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 "util.h"
00065
00066 #if !defined HAVE_LSTAT && !defined lstat
00067 #define lstat stat
00068 #endif
00069
00070 #define FNM_NOESCAPE 0x01
00071 #define FNM_PATHNAME 0x02
00072 #define FNM_DOTMATCH 0x04
00073 #define FNM_CASEFOLD 0x08
00074
00075 #define FNM_NOMATCH 1
00076 #define FNM_ERROR 2
00077
00078 #define downcase(c) (nocase && ISUPPER(c) ? tolower(c) : (c))
00079
00080 #ifndef CharNext
00081 # if defined(DJGPP)
00082 # define CharNext(p) ((p) + mblen(p, MB_CUR_MAX))
00083 # else
00084 # define CharNext(p) ((p) + 1)
00085 # endif
00086 #endif
00087
00088 #if defined DOSISH
00089 #define isdirsep(c) ((c) == '/' || (c) == '\\')
00090 #else
00091 #define isdirsep(c) ((c) == '/')
00092 #endif
00093
00094 static char *
00095 range(pat, test, flags)
00096 const char *pat;
00097 int test;
00098 int flags;
00099 {
00100 int not, ok = 0;
00101 int nocase = flags & FNM_CASEFOLD;
00102 int escape = !(flags & FNM_NOESCAPE);
00103
00104 not = *pat == '!' || *pat == '^';
00105 if (not)
00106 pat++;
00107
00108 test = downcase(test);
00109
00110 while (*pat != ']') {
00111 int cstart, cend;
00112 if (escape && *pat == '\\')
00113 pat++;
00114 cstart = cend = *pat++;
00115 if (!cstart)
00116 return NULL;
00117 if (*pat == '-' && pat[1] != ']') {
00118 pat++;
00119 if (escape && *pat == '\\')
00120 pat++;
00121 cend = *pat++;
00122 if (!cend)
00123 return NULL;
00124 }
00125 if (downcase(cstart) <= test && test <= downcase(cend))
00126 ok = 1;
00127 }
00128 return ok == not ? NULL : (char *)pat + 1;
00129 }
00130
00131 #define ISDIRSEP(c) (pathname && isdirsep(c))
00132 #define PERIOD(s) (period && *(s) == '.' && \
00133 ((s) == string || ISDIRSEP((s)[-1])))
00134 static int
00135 fnmatch(pat, string, flags)
00136 const char *pat;
00137 const char *string;
00138 int flags;
00139 {
00140 int c;
00141 int test;
00142 const char *s = string;
00143 int escape = !(flags & FNM_NOESCAPE);
00144 int pathname = flags & FNM_PATHNAME;
00145 int period = !(flags & FNM_DOTMATCH);
00146 int nocase = flags & FNM_CASEFOLD;
00147
00148 while (c = *pat++) {
00149 switch (c) {
00150 case '?':
00151 if (!*s || ISDIRSEP(*s) || PERIOD(s))
00152 return FNM_NOMATCH;
00153 s++;
00154 break;
00155 case '*':
00156 while ((c = *pat++) == '*')
00157 ;
00158
00159 if (PERIOD(s))
00160 return FNM_NOMATCH;
00161
00162 if (!c) {
00163 if (pathname && *rb_path_next(s))
00164 return FNM_NOMATCH;
00165 else
00166 return 0;
00167 }
00168 else if (ISDIRSEP(c)) {
00169 s = rb_path_next(s);
00170 if (*s) {
00171 s++;
00172 break;
00173 }
00174 return FNM_NOMATCH;
00175 }
00176
00177 test = escape && c == '\\' ? *pat : c;
00178 test = downcase(test);
00179 pat--;
00180 while (*s) {
00181 if ((c == '?' || c == '[' || downcase(*s) == test) &&
00182 !fnmatch(pat, s, flags | FNM_DOTMATCH))
00183 return 0;
00184 else if (ISDIRSEP(*s))
00185 break;
00186 s++;
00187 }
00188 return FNM_NOMATCH;
00189
00190 case '[':
00191 if (!*s || ISDIRSEP(*s) || PERIOD(s))
00192 return FNM_NOMATCH;
00193 pat = range(pat, *s, flags);
00194 if (pat == NULL)
00195 return FNM_NOMATCH;
00196 s++;
00197 break;
00198
00199 case '\\':
00200 if (escape
00201 #if defined DOSISH
00202 && *pat && strchr("*?[]\\", *pat)
00203 #endif
00204 ) {
00205 c = *pat;
00206 if (!c)
00207 c = '\\';
00208 else
00209 pat++;
00210 }
00211
00212
00213 default:
00214 #if defined DOSISH
00215 if (ISDIRSEP(c) && isdirsep(*s))
00216 ;
00217 else
00218 #endif
00219 if(downcase(c) != downcase(*s))
00220 return FNM_NOMATCH;
00221 s++;
00222 break;
00223 }
00224 }
00225 return !*s ? 0 : FNM_NOMATCH;
00226 }
00227
00228 VALUE rb_cDir;
00229
00230 struct dir_data {
00231 DIR *dir;
00232 char *path;
00233 };
00234
00235 static void
00236 free_dir(dir)
00237 struct dir_data *dir;
00238 {
00239 if (dir) {
00240 if (dir->dir) closedir(dir->dir);
00241 if (dir->path) free(dir->path);
00242 }
00243 free(dir);
00244 }
00245
00246 static VALUE dir_close (VALUE);
00247
00248 static VALUE dir_s_alloc (VALUE);
00249 static VALUE
00250 dir_s_alloc(klass)
00251 VALUE klass;
00252 {
00253 struct dir_data *dirp;
00254 VALUE obj = Data_Make_Struct(klass, struct dir_data, 0, free_dir, dirp);
00255
00256 dirp->dir = NULL;
00257 dirp->path = NULL;
00258
00259 return obj;
00260 }
00261
00262
00263
00264
00265
00266
00267
00268 static VALUE
00269 dir_initialize(dir, dirname)
00270 VALUE dir, dirname;
00271 {
00272 struct dir_data *dp;
00273
00274 SafeStringValue(dirname);
00275 Data_Get_Struct(dir, struct dir_data, dp);
00276 if (dp->dir) closedir(dp->dir);
00277 if (dp->path) free(dp->path);
00278 dp->dir = NULL;
00279 dp->path = NULL;
00280 dp->dir = opendir(RSTRING(dirname)->ptr);
00281 if (dp->dir == NULL) {
00282 if (errno == EMFILE || errno == ENFILE) {
00283 rb_gc();
00284 dp->dir = opendir(RSTRING(dirname)->ptr);
00285 }
00286 if (dp->dir == NULL) {
00287 rb_sys_fail(RSTRING(dirname)->ptr);
00288 }
00289 }
00290 dp->path = strdup(RSTRING(dirname)->ptr);
00291
00292 return dir;
00293 }
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307 static VALUE
00308 dir_s_open(klass, dirname)
00309 VALUE klass, dirname;
00310 {
00311 struct dir_data *dp;
00312 VALUE dir = Data_Make_Struct(klass, struct dir_data, 0, free_dir, dp);
00313
00314 dir_initialize(dir, dirname);
00315 if (rb_block_given_p()) {
00316 return rb_ensure(rb_yield, dir, dir_close, dir);
00317 }
00318
00319 return dir;
00320 }
00321
00322 static void
00323 dir_closed()
00324 {
00325 rb_raise(rb_eIOError, "closed directory");
00326 }
00327
00328 #define GetDIR(obj, dirp) do {\
00329 Data_Get_Struct(obj, struct dir_data, dirp);\
00330 if (dirp->dir == NULL) dir_closed();\
00331 } while (0)
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342 static VALUE
00343 dir_path(dir)
00344 VALUE dir;
00345 {
00346 struct dir_data *dirp;
00347
00348 GetDIR(dir, dirp);
00349 if (!dirp->path) return Qnil;
00350 return rb_str_new2(dirp->path);
00351 }
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365 static VALUE
00366 dir_read(dir)
00367 VALUE dir;
00368 {
00369 struct dir_data *dirp;
00370 struct dirent *dp;
00371
00372 GetDIR(dir, dirp);
00373 errno = 0;
00374 dp = readdir(dirp->dir);
00375 if (dp) {
00376 return rb_tainted_str_new(dp->d_name, NAMLEN(dp));
00377 }
00378 else if (errno == 0) {
00379 return Qnil;
00380 }
00381 else {
00382 rb_sys_fail(0);
00383 }
00384 return Qnil;
00385 }
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404 static VALUE
00405 dir_each(dir)
00406 VALUE dir;
00407 {
00408 struct dir_data *dirp;
00409 struct dirent *dp;
00410
00411 GetDIR(dir, dirp);
00412 rewinddir(dirp->dir);
00413 for (dp = readdir(dirp->dir); dp != NULL; dp = readdir(dirp->dir)) {
00414 rb_yield(rb_tainted_str_new(dp->d_name, NAMLEN(dp)));
00415 if (dirp->dir == NULL) dir_closed();
00416 }
00417 return dir;
00418 }
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433 static VALUE
00434 dir_tell(dir)
00435 VALUE dir;
00436 {
00437 #ifdef HAVE_TELLDIR
00438 struct dir_data *dirp;
00439 long pos;
00440
00441 GetDIR(dir, dirp);
00442 pos = telldir(dirp->dir);
00443 return rb_int2inum(pos);
00444 #else
00445 rb_notimplement();
00446 #endif
00447 }
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463 static VALUE
00464 dir_seek(dir, pos)
00465 VALUE dir, pos;
00466 {
00467 struct dir_data *dirp;
00468 off_t p = NUM2OFFT(pos);
00469
00470 GetDIR(dir, dirp);
00471 #ifdef HAVE_SEEKDIR
00472 seekdir(dirp->dir, p);
00473 return dir;
00474 #else
00475 rb_notimplement();
00476 #endif
00477 }
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493 static VALUE
00494 dir_set_pos(dir, pos)
00495 VALUE dir, pos;
00496 {
00497 dir_seek(dir, pos);
00498 return pos;
00499 }
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512 static VALUE
00513 dir_rewind(dir)
00514 VALUE dir;
00515 {
00516 struct dir_data *dirp;
00517
00518 GetDIR(dir, dirp);
00519 rewinddir(dirp->dir);
00520 return dir;
00521 }
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533 static VALUE
00534 dir_close(dir)
00535 VALUE dir;
00536 {
00537 struct dir_data *dirp;
00538
00539 GetDIR(dir, dirp);
00540 closedir(dirp->dir);
00541 dirp->dir = NULL;
00542
00543 return Qnil;
00544 }
00545
00546 static void
00547 dir_chdir(path)
00548 VALUE path;
00549 {
00550 if (chdir(RSTRING(path)->ptr) < 0)
00551 rb_sys_fail(RSTRING(path)->ptr);
00552 }
00553
00554 static int chdir_blocking = 0;
00555 static VALUE chdir_thread = Qnil;
00556
00557 struct chdir_data {
00558 VALUE old_path, new_path;
00559 int done;
00560 };
00561
00562 static VALUE
00563 chdir_yield(args)
00564 struct chdir_data *args;
00565 {
00566 dir_chdir(args->new_path);
00567 args->done = Qtrue;
00568 chdir_blocking++;
00569 if (chdir_thread == Qnil)
00570 chdir_thread = rb_thread_current();
00571 return rb_yield(args->new_path);
00572 }
00573
00574 static VALUE
00575 chdir_restore(args)
00576 struct chdir_data *args;
00577 {
00578 if (args->done) {
00579 chdir_blocking--;
00580 if (chdir_blocking == 0)
00581 chdir_thread = Qnil;
00582 dir_chdir(args->old_path);
00583 }
00584 return Qnil;
00585 }
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626 static VALUE
00627 dir_s_chdir(argc, argv, obj)
00628 int argc;
00629 VALUE *argv;
00630 VALUE obj;
00631 {
00632 VALUE path = Qnil;
00633
00634 rb_secure(2);
00635 if (rb_scan_args(argc, argv, "01", &path) == 1) {
00636 SafeStringValue(path);
00637 }
00638 else {
00639 const char *dist = getenv("HOME");
00640 if (!dist) {
00641 dist = getenv("LOGDIR");
00642 if (!dist) rb_raise(rb_eArgError, "HOME/LOGDIR not set");
00643 }
00644 path = rb_str_new2(dist);
00645 }
00646
00647 if (chdir_blocking > 0) {
00648 if (!rb_block_given_p() || rb_thread_current() != chdir_thread)
00649 rb_warn("conflicting chdir during another chdir block");
00650 }
00651
00652 if (rb_block_given_p()) {
00653 struct chdir_data args;
00654 char *cwd = my_getcwd();
00655
00656 args.old_path = rb_tainted_str_new2(cwd); free(cwd);
00657 args.new_path = path;
00658 args.done = Qfalse;
00659 return rb_ensure(chdir_yield, (VALUE)&args, chdir_restore, (VALUE)&args);
00660 }
00661 dir_chdir(path);
00662
00663 return INT2FIX(0);
00664 }
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677 static VALUE
00678 dir_s_getwd(dir)
00679 VALUE dir;
00680 {
00681 char *path;
00682 VALUE cwd;
00683
00684 rb_secure(4);
00685 path = my_getcwd();
00686 cwd = rb_tainted_str_new2(path);
00687
00688 free(path);
00689 return cwd;
00690 }
00691
00692 static void check_dirname (volatile VALUE *);
00693 static void
00694 check_dirname(dir)
00695 volatile VALUE *dir;
00696 {
00697 char *path, *pend;
00698
00699 SafeStringValue(*dir);
00700 rb_secure(2);
00701 path = RSTRING(*dir)->ptr;
00702 if (path && *(pend = rb_path_end(rb_path_skip_prefix(path)))) {
00703 *dir = rb_str_new(path, pend - path);
00704 }
00705 }
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716 static VALUE
00717 dir_s_chroot(dir, path)
00718 VALUE dir, path;
00719 {
00720 #if defined(HAVE_CHROOT) && !defined(__CHECKER__)
00721 check_dirname(&path);
00722
00723 if (chroot(RSTRING(path)->ptr) == -1)
00724 rb_sys_fail(RSTRING(path)->ptr);
00725
00726 return INT2FIX(0);
00727 #else
00728 rb_notimplement();
00729 return Qnil;
00730 #endif
00731 }
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746 static VALUE
00747 dir_s_mkdir(argc, argv, obj)
00748 int argc;
00749 VALUE *argv;
00750 VALUE obj;
00751 {
00752 VALUE path, vmode;
00753 int mode;
00754
00755 if (rb_scan_args(argc, argv, "11", &path, &vmode) == 2) {
00756 mode = NUM2INT(vmode);
00757 }
00758 else {
00759 mode = 0777;
00760 }
00761
00762 check_dirname(&path);
00763 if (mkdir(RSTRING(path)->ptr, mode) == -1)
00764 rb_sys_fail(RSTRING(path)->ptr);
00765
00766 return INT2FIX(0);
00767 }
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778 static VALUE
00779 dir_s_rmdir(obj, dir)
00780 VALUE obj, dir;
00781 {
00782 check_dirname(&dir);
00783 if (rmdir(RSTRING(dir)->ptr) < 0)
00784 rb_sys_fail(RSTRING(dir)->ptr);
00785
00786 return INT2FIX(0);
00787 }
00788
00789 #define GLOB_VERBOSE (1 << (sizeof(int) * CHAR_BIT - 1))
00790 #define sys_warning(val) \
00791 ((flags & GLOB_VERBOSE) && rb_protect((VALUE (*)(VALUE))rb_sys_warning, (VALUE)(val), 0))
00792
00793
00794 static int
00795 has_magic(s, send, flags)
00796 const char *s, *send;
00797 int flags;
00798 {
00799 register const char *p = s;
00800 register char c;
00801 int open = 0;
00802 int escape = !(flags & FNM_NOESCAPE);
00803
00804 while ((c = *p++) != '\0') {
00805 switch (c) {
00806 case '?':
00807 case '*':
00808 return Qtrue;
00809
00810 case '[':
00811 open++;
00812 continue;
00813 case ']':
00814 if (open)
00815 return Qtrue;
00816 continue;
00817
00818 case '\\':
00819 if (escape && *p++ == '\0')
00820 return Qfalse;
00821 }
00822
00823 if (send && p >= send) break;
00824 }
00825 return Qfalse;
00826 }
00827
00828 static char*
00829 extract_path(p, pend)
00830 const char *p, *pend;
00831 {
00832 char *alloc;
00833 int len;
00834
00835 len = pend - p;
00836 alloc = ALLOC_N(char, len+1);
00837 memcpy(alloc, p, len);
00838 if (len > 1 && pend[-1] == '/'
00839 #if defined DOSISH_DRIVE_LETTER
00840 && pend[-2] != ':'
00841 #endif
00842 ) {
00843 alloc[len-1] = 0;
00844 }
00845 else {
00846 alloc[len] = 0;
00847 }
00848
00849 return alloc;
00850 }
00851
00852 static char*
00853 extract_elem(path)
00854 const char *path;
00855 {
00856 const char *pend;
00857
00858 pend = strchr(path, '/');
00859 if (!pend) pend = path + strlen(path);
00860
00861 return extract_path(path, pend);
00862 }
00863
00864 static void
00865 remove_backslashes(p)
00866 char *p;
00867 {
00868 char *pend = p + strlen(p);
00869 char *t = p;
00870
00871 while (p < pend) {
00872 if (*p == '\\') {
00873 if (++p == pend) break;
00874 }
00875 *t++ = *p++;
00876 }
00877 *t = '\0';
00878 }
00879
00880 #ifndef S_ISDIR
00881 # define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR)
00882 #endif
00883
00884 struct glob_args {
00885 void (*func) (const char*, VALUE);
00886 const char *c;
00887 VALUE v;
00888 };
00889
00890 static VALUE glob_func_caller (VALUE);
00891
00892 static VALUE
00893 glob_func_caller(val)
00894 VALUE val;
00895 {
00896 struct glob_args *args = (struct glob_args *)val;
00897
00898 (*args->func)(args->c, args->v);
00899 return Qnil;
00900 }
00901
00902 #define glob_call_func(func, path, arg) (*func)(path, arg)
00903
00904 static int glob_helper (const char *path, const char *sub, int flags, int (*func(const char *,VALUE), VALUE arg));
00905
00906 static int
00907 glob_helper(path, sub, flags, func, arg)
00908 const char *path;
00909 const char *sub;
00910 int flags;
00911 int (*func) (const char *, VALUE);
00912 VALUE arg;
00913 {
00914 struct stat st;
00915 const char *p, *m;
00916 int status = 0;
00917 char *buf = 0;
00918 char *newpath = 0;
00919
00920 p = sub ? sub : path;
00921 if (!has_magic(p, 0, flags)) {
00922 if (
00923 #if defined DOSISH
00924 TRUE
00925 #else
00926 !(flags & FNM_NOESCAPE)
00927 #endif
00928 )
00929 {
00930 newpath = strdup(path);
00931 if (sub) {
00932 p = newpath + (sub - path);
00933 remove_backslashes(newpath + (sub - path));
00934 sub = p;
00935 }
00936 else {
00937 remove_backslashes(newpath);
00938 p = path = newpath;
00939 }
00940 }
00941 if (lstat(path, &st) == 0) {
00942 status = glob_call_func(func, path, arg);
00943 }
00944 else if (errno != ENOENT) {
00945
00946
00947 sys_warning(path);
00948 }
00949 xfree(newpath);
00950 return status;
00951 }
00952
00953 while (p && !status) {
00954 if (*p == '/') p++;
00955 m = strchr(p, '/');
00956 if (has_magic(p, m, flags)) {
00957 char *dir, *base, *magic;
00958 DIR *dirp;
00959 struct dirent *dp;
00960 int recursive = 0;
00961
00962 struct d_link {
00963 char *path;
00964 struct d_link *next;
00965 } *tmp, *link, **tail = &link;
00966
00967 base = extract_path(path, p);
00968 if (path == p) dir = ".";
00969 else dir = base;
00970
00971 magic = extract_elem(p);
00972 if (stat(dir, &st) < 0) {
00973 if (errno != ENOENT)
00974 sys_warning(dir);
00975 free(base);
00976 free(magic);
00977 break;
00978 }
00979 if (S_ISDIR(st.st_mode)) {
00980 if (m && strcmp(magic, "**") == 0) {
00981 int n = strlen(base);
00982 recursive = 1;
00983 REALLOC_N(buf, char, n+strlen(m)+3);
00984 sprintf(buf, "%s%s", base, *base ? m : m+1);
00985 status = glob_helper(buf, buf+n, flags, func, arg);
00986 if (status) goto finalize;
00987 }
00988 dirp = opendir(dir);
00989 if (dirp == NULL) {
00990 sys_warning(dir);
00991 free(base);
00992 free(magic);
00993 break;
00994 }
00995 }
00996 else {
00997 free(base);
00998 free(magic);
00999 break;
01000 }
01001
01002 #if defined DOSISH_DRIVE_LETTER
01003 #define BASE (*base && !((isdirsep(*base) && !base[1]) || (base[1] == ':' && isdirsep(base[2]) && !base[3])))
01004 #else
01005 #define BASE (*base && !(isdirsep(*base) && !base[1]))
01006 #endif
01007
01008 for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
01009 if (recursive) {
01010 if (strcmp(".", dp->d_name) == 0 || strcmp("..", dp->d_name) == 0)
01011 continue;
01012 if (fnmatch("*", dp->d_name, flags) != 0)
01013 continue;
01014 REALLOC_N(buf, char, strlen(base)+NAMLEN(dp)+strlen(m)+6);
01015 sprintf(buf, "%s%s%s", base, (BASE) ? "/" : "", dp->d_name);
01016 if (lstat(buf, &st) < 0) {
01017 if (errno != ENOENT)
01018 sys_warning(buf);
01019 continue;
01020 }
01021 if (S_ISDIR(st.st_mode)) {
01022 char *t = buf+strlen(buf);
01023 strcpy(t, "
01208 if (*p == '{') {
01209 nest = 1;
01210 while (*++p != '}' || --nest) {
01211 if (*p == '{') nest++;
01212 }
01213 }
01214 }
01215 REALLOC_N(buf, char, len+1);
01216 memcpy(buf, s, lbrace-s);
01217 b = buf + (lbrace-s);
01218 memcpy(b, t, p-t);
01219 strcpy(b+(p-t), rbrace+1);
01220 status = push_braces(ary, buf, flags);
01221 if (status) break;
01222 }
01223 }
01224 else {
01225 status = push_globs(ary, str, flags);
01226 }
01227 xfree(buf);
01228
01229 return status;
01230 }
01231
01232 #define isdelim(c) ((c)=='\0')
01233
01234 static VALUE
01235 rb_push_glob(str, flags)
01236 VALUE str;
01237 int flags;
01238 {
01239 const char *p, *pend, *buf;
01240 int nest, maxnest;
01241 int status = 0;
01242 int noescape = flags & FNM_NOESCAPE;
01243 VALUE ary;
01244
01245 ary = rb_ary_new();
01246 SafeStringValue(str);
01247 p = RSTRING(str)->ptr;
01248 pend = p + RSTRING(str)->len;
01249
01250 while (p < pend) {
01251 nest = maxnest = 0;
01252 while (p < pend && isdelim(*p)) p++;
01253 buf = p;
01254 while (p < pend && !isdelim(*p)) {
01255 if (*p == '{') nest++, maxnest++;
01256 if (*p == '}') nest--;
01257 if (!noescape && *p == '\\') {
01258 if (++p == pend) break;
01259 }
01260 p++;
01261 }
01262 if (maxnest == 0) {
01263 status = push_globs(ary, buf, flags);
01264 if (status) break;
01265 }
01266 else if (nest == 0) {
01267 status = push_braces(ary, buf, flags);
01268 if (status) break;
01269 }
01270 /* else unmatched braces */
01271 }
01272 if (status) rb_jump_tag(status);
01273 if (rb_block_given_p()) {
01274 rb_ary_each(ary);
01275 return Qnil;
01276 }
01277 return ary;
01278 }
01279
01280 /*
01281 * call-seq:
01282 * Dir[ string ] => array
01283 *
01284 * Equivalent to calling
01285 * <em>dir</em>.<code>glob(</code><i>string,</i><code>0)</code>.
01286 *
01287 */
01288 static VALUE
01289 dir_s_aref(obj, str)
01290 VALUE obj, str;
01291 {
01292 return rb_push_glob(str, 0);
01293 }
01294
01295 /*
01296 * call-seq:
01297 * Dir.glob( string, [flags] ) => array
01298 * Dir.glob( string, [flags] ) {| filename | block } => nil
01299 *
01300 * Returns the filenames found by expanding the pattern given in
01301 * <i>string</i>, either as an <i>array</i> or as parameters to the
01302 * block. Note that this pattern is not a regexp (it's closer to a
01303 * shell glob). See <code>File::fnmatch</code> for the meaning of
01304 * the <i>flags</i> parameter.
01305 *
01306 * <code>*</code>:: Matches any file. Can be restricted by
01307 * other values in the glob. <code>*</code>
01308 * will match all files; <code>c*</code> will
01309 * match all files beginning with
01310 * <code>c</code>; <code>*c</code> will match
01311 * all files ending with <code>c</code>; and
01312 * <code>*c*</code> will match all files that
01313 * have <code>c</code> in them (including at
01314 * the beginning or end). Equivalent to
01315 * <code>/ .* /x</code> in regexp.
01316 * <code>**</code>:: Matches directories recursively.
01317 * <code>?</code>:: Matches any one character. Equivalent to
01318 * <code>/.{1}/</code> in regexp.
01319 * <code>[set]</code>:: Matches any one character in +set+.
01320 * Behaves exactly like character sets in
01321 * Regexp, including set negation
01322 * (<code>[^a-z]</code>).
01323 * <code>{p,q}</code>:: Matches either literal <code>p</code> or
01324 * literal <code>q</code>. Matching literals
01325 * may be more than one character in length.
01326 * More than two literals may be specified.
01327 * Equivalent to pattern alternation in
01328 * regexp.
01329 * <code></code>:: Escapes the next metacharacter.
01330 *
01331 * Dir["config.?"] #=> ["config.h"]
01332 * Dir.glob("config.?") #=> ["config.h"]
01333 * Dir.glob("*.[a-z][a-z]") #=> ["main.rb"]
01334 * Dir.glob("*.[^r]*") #=> ["config.h"]
01335 * Dir.glob("*.{rb,h}") #=> ["main.rb", "config.h"]
01336 * Dir.glob("*") #=> ["config.h", "main.rb"]
01337 * Dir.glob("*", File::FNM_DOTMATCH) #=> [".", "..", "config.h", "main.rb"]
01338 *
01339 * rbfiles = File.join("**", "*.rb")
01340 * Dir.glob(rbfiles) #=> ["main.rb",
01341 * "lib/song.rb",
01342 * "lib/song/karaoke.rb"]
01343 * libdirs = File.join("**", "lib")
01344 * Dir.glob(libdirs) #=> ["lib"]
01345 *
01346 * librbfiles = File.join("**", "lib", "**", "*.rb")
01347 * Dir.glob(librbfiles) #=> ["lib/song.rb",
01348 * "lib/song/karaoke.rb"]
01349 *
01350 * librbfiles = File.join("**", "lib", "*.rb")
01351 * Dir.glob(librbfiles) #=> ["lib/song.rb"]
01352 */
01353 static VALUE
01354 dir_s_glob(argc, argv, obj)
01355 int argc;
01356 VALUE *argv;
01357 VALUE obj;
01358 {
01359 VALUE str, rflags;
01360 int flags;
01361
01362 if (rb_scan_args(argc, argv, "11", &str, &rflags) == 2)
01363 flags = NUM2INT(rflags);
01364 else
01365 flags = 0;
01366
01367 return rb_push_glob(str, flags);
01368 }
01369
01370 static VALUE
01371 dir_open_dir(path)
01372 VALUE path;
01373 {
01374 VALUE dir = rb_funcall(rb_cDir, rb_intern("open"), 1, path);
01375
01376 if (TYPE(dir) != T_DATA ||
01377 RDATA(dir)->dfree != (RUBY_DATA_FUNC)free_dir) {
01378 rb_raise(rb_eTypeError, "wrong argument type %s (expected Dir)",
01379 rb_obj_classname(dir));
01380 }
01381 return dir;
01382 }
01383
01384
01385 /*
01386 * call-seq:
01387 * Dir.foreach( dirname ) {| filename | block } => nil
01388 *
01389 * Calls the block once for each entry in the named directory, passing
01390 * the filename of each entry as a parameter to the block.
01391 *
01392 * Dir.foreach("testdir") {|x| puts "Got #{x}" }
01393 *
01394 * <em>produces:</em>
01395 *
01396 * Got .
01397 * Got ..
01398 * Got config.h
01399 * Got main.rb
01400 *
01401 */
01402 static VALUE
01403 dir_foreach(io, dirname)
01404 VALUE io, dirname;
01405 {
01406 VALUE dir;
01407
01408 dir = dir_open_dir(dirname);
01409 rb_ensure(dir_each, dir, dir_close, dir);
01410 return Qnil;
01411 }
01412
01413 /*
01414 * call-seq:
01415 * Dir.entries( dirname ) => array
01416 *
01417 * Returns an array containing all of the filenames in the given
01418 * directory. Will raise a <code>SystemCallError</code> if the named
01419 * directory doesn't exist.
01420 *
01421 * Dir.entries("testdir") #=> [".", "..", "config.h", "main.rb"]
01422 *
01423 */
01424 static VALUE
01425 dir_entries(io, dirname)
01426 VALUE io, dirname;
01427 {
01428 VALUE dir;
01429
01430 dir = dir_open_dir(dirname);
01431 return rb_ensure(rb_Array, dir, dir_close, dir);
01432 }
01433
01434 /*
01435 * call-seq:
01436 * File.fnmatch( pattern, path, [flags] ) => (true or false)
01437 * File.fnmatch?( pattern, path, [flags] ) => (true or false)
01438 *
01439 * Returns true if <i>path</i> matches against <i>pattern</i> The
01440 * pattern is not a regular expression; instead it follows rules
01441 * similar to shell filename globbing. It may contain the following
01442 * metacharacters:
01443 *
01444 * <code>*</code>:: Matches any file. Can be restricted by
01445 * other values in the glob. <code>*</code>
01446 * will match all files; <code>c*</code> will
01447 * match all files beginning with
01448 * <code>c</code>; <code>*c</code> will match
01449 * all files ending with <code>c</code>; and
01450 * <code>*c*</code> will match all files that
01451 * have <code>c</code> in them (including at
01452 * the beginning or end). Equivalent to
01453 * <code>/ .* /x</code> in regexp.
01454 * <code>?</code>:: Matches any one character. Equivalent to
01455 * <code>/.{1}/</code> in regexp.
01456 * <code>[set]</code>:: Matches any one character in +set+.
01457 * Behaves exactly like character sets in
01458 * Regexp, including set negation
01459 * (<code>[^a-z]</code>).
01460 * <code></code>:: Escapes the next metacharacter.
01461 *
01462 * <i>flags</i> is a bitwise OR of the <code>FNM_xxx</code>
01463 * parameters. The same glob pattern and flags are used by
01464 * <code>Dir::glob</code>.
01465 *
01466 * File.fnmatch('cat', 'cat') #=> true
01467 * File.fnmatch('cat', 'category') #=> false
01468 * File.fnmatch('c{at,ub}s', 'cats') #=> false
01469 * File.fnmatch('c{at,ub}s', 'cubs') #=> false
01470 * File.fnmatch('c{at,ub}s', 'cat') #=> false
01471 *
01472 * File.fnmatch('c?t', 'cat') #=> true
01473 * File.fnmatch('c\?t', 'cat') #=> false
01474 * File.fnmatch('c??t', 'cat') #=> false
01475 * File.fnmatch('c*', 'cats') #=> true
01476 * File.fnmatch('c/ * FIXME * /t', 'c/a/b/c/t') #=> true
01477 * File.fnmatch('c*t', 'cat') #=> true
01478 * File.fnmatch('c\at', 'cat') #=> true
01479 * File.fnmatch('c\at', 'cat', File::FNM_NOESCAPE) #=> false
01480 * File.fnmatch('a?b', 'a/b') #=> true
01481 * File.fnmatch('a?b', 'a/b', File::FNM_PATHNAME) #=> false
01482 *
01483 * File.fnmatch('*', '.profile') #=> false
01484 * File.fnmatch('*', '.profile', File::FNM_DOTMATCH) #=> true
01485 * File.fnmatch('*', 'dave/.profile') #=> true
01486 * File.fnmatch('*', 'dave/.profile', File::FNM_DOTMATCH) #=> true
01487 * File.fnmatch('*', 'dave/.profile', File::FNM_PATHNAME) #=> false
01488 * File.fnmatch('* / FIXME *', 'dave/.profile', File::FNM_PATHNAME) #=> false
01489 * STRICT = File::FNM_PATHNAME | File::FNM_DOTMATCH
01490 * File.fnmatch('* / FIXME *', 'dave/.profile', STRICT) #=> true
01491 */
01492 static VALUE
01493 file_s_fnmatch(argc, argv, obj)
01494 int argc;
01495 VALUE *argv;
01496 VALUE obj;
01497 {
01498 VALUE pattern, path;
01499 VALUE rflags;
01500 int flags;
01501
01502 if (rb_scan_args(argc, argv, "21", &pattern, &path, &rflags) == 3)
01503 flags = NUM2INT(rflags);
01504 else
01505 flags = 0;
01506
01507 StringValue(pattern);
01508 StringValue(path);
01509
01510 if (fnmatch(RSTRING(pattern)->ptr, RSTRING(path)->ptr, flags) == 0)
01511 return Qtrue;
01512
01513 return Qfalse;
01514 }
01515
01516 /*
01517 * Objects of class <code>Dir</code> are directory streams representing
01518 * directories in the underlying file system. They provide a variety of
01519 * ways to list directories and their contents. See also
01520 * <code>File</code>.
01521 *
01522 * The directory used in these examples contains the two regular files
01523 * (<code>config.h</code> and <code>main.rb</code>), the parent
01524 * directory (<code>..</code>), and the directory itself
01525 * (<code>.</code>).
01526 */
01527 void
01528 Init_Dir()
01529 {
01530 rb_cDir = rb_define_class("Dir", rb_cObject);
01531
01532 rb_include_module(rb_cDir, rb_mEnumerable);
01533
01534 rb_define_alloc_func(rb_cDir, dir_s_alloc);
01535 rb_define_singleton_method(rb_cDir, "open", dir_s_open, 1);
01536 rb_define_singleton_method(rb_cDir, "foreach", dir_foreach, 1);
01537 rb_define_singleton_method(rb_cDir, "entries", dir_entries, 1);
01538
01539 rb_define_method(rb_cDir,"initialize", dir_initialize, 1);
01540 rb_define_method(rb_cDir,"path", dir_path, 0);
01541 rb_define_method(rb_cDir,"read", dir_read, 0);
01542 rb_define_method(rb_cDir,"each", dir_each, 0);
01543 rb_define_method(rb_cDir,"rewind", dir_rewind, 0);
01544 rb_define_method(rb_cDir,"tell", dir_tell, 0);
01545 rb_define_method(rb_cDir,"seek", dir_seek, 1);
01546 rb_define_method(rb_cDir,"pos", dir_tell, 0);
01547 rb_define_method(rb_cDir,"pos=", dir_set_pos, 1);
01548 rb_define_method(rb_cDir,"close", dir_close, 0);
01549
01550 rb_define_singleton_method(rb_cDir,"chdir", dir_s_chdir, -1);
01551 rb_define_singleton_method(rb_cDir,"getwd", dir_s_getwd, 0);
01552 rb_define_singleton_method(rb_cDir,"pwd", dir_s_getwd, 0);
01553 rb_define_singleton_method(rb_cDir,"chroot", dir_s_chroot, 1);
01554 rb_define_singleton_method(rb_cDir,"mkdir", dir_s_mkdir, -1);
01555 rb_define_singleton_method(rb_cDir,"rmdir", dir_s_rmdir, 1);
01556 rb_define_singleton_method(rb_cDir,"delete", dir_s_rmdir, 1);
01557 rb_define_singleton_method(rb_cDir,"unlink", dir_s_rmdir, 1);
01558
01559 rb_define_singleton_method(rb_cDir,"glob", dir_s_glob, -1);
01560 rb_define_singleton_method(rb_cDir,"[]", dir_s_aref, 1);
01561
01562 rb_define_singleton_method(rb_cFile,"fnmatch", file_s_fnmatch, -1);
01563 rb_define_singleton_method(rb_cFile,"fnmatch?", file_s_fnmatch, -1);
01564
01565 rb_file_const("FNM_NOESCAPE", INT2FIX(FNM_NOESCAPE));
01566 rb_file_const("FNM_PATHNAME", INT2FIX(FNM_PATHNAME));
01567 rb_file_const("FNM_DOTMATCH", INT2FIX(FNM_DOTMATCH));
01568 rb_file_const("FNM_CASEFOLD", INT2FIX(FNM_CASEFOLD));
01569 }
01570