Ruby 2.0.0p247(2013-06-27revision41674)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

dir.c
Go to the documentation of this file.
1 /**********************************************************************
2
3 dir.c -
4
5 $Author: nagachika $
6 created at: Wed Jan 5 09:51:01 JST 1994
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 Copyright (C) 2000 Information-technology Promotion Agency, Japan
11
12 **********************************************************************/
13
14 #include "ruby/ruby.h"
15 #include "ruby/encoding.h"
16 #include "internal.h"
17
18 #include <sys/types.h>
19 #include <sys/stat.h>
20
21 #ifdef HAVE_UNISTD_H
22 #include <unistd.h>
23 #endif
24
25 #if defined HAVE_DIRENT_H && !defined _WIN32
26 # include <dirent.h>
27 # define NAMLEN(dirent) strlen((dirent)->d_name)
28 #elif defined HAVE_DIRECT_H && !defined _WIN32
29 # include <direct.h>
30 # define NAMLEN(dirent) strlen((dirent)->d_name)
31 #else
32 # define dirent direct
33 # define NAMLEN(dirent) (dirent)->d_namlen
34 # if HAVE_SYS_NDIR_H
35 # include <sys/ndir.h>
36 # endif
37 # if HAVE_SYS_DIR_H
38 # include <sys/dir.h>
39 # endif
40 # if HAVE_NDIR_H
41 # include <ndir.h>
42 # endif
43 # ifdef _WIN32
44 # include "win32/dir.h"
45 # endif
46 #endif
47 #if defined(__native_client__) && defined(NACL_NEWLIB)
48 # include "nacl/dirent.h"
49 # include "nacl/stat.h"
50 #endif
51
52 #include <errno.h>
53
54 #ifndef HAVE_STDLIB_H
55 char *getenv();
56 #endif
57
58 #ifndef HAVE_STRING_H
59 char *strchr(char*,char);
60 #endif
61
62 #include <ctype.h>
63
64 #include "ruby/util.h"
65
66 #if !defined HAVE_LSTAT && !defined lstat
67 #define lstat stat
68 #endif
69
70 /* define system APIs */
71 #ifdef _WIN32
72 #undef chdir
73 #define chdir(p) rb_w32_uchdir(p)
74 #undef mkdir
75 #define mkdir(p, m) rb_w32_umkdir((p), (m))
76 #undef rmdir
77 #define rmdir(p) rb_w32_urmdir(p)
78 #undef opendir
79 #define opendir(p) rb_w32_uopendir(p)
80 #endif
81
82 #define rb_sys_fail_path(path) rb_sys_fail_str(path)
83
84 #define FNM_NOESCAPE 0x01
85 #define FNM_PATHNAME 0x02
86 #define FNM_DOTMATCH 0x04
87 #define FNM_CASEFOLD 0x08
88 #define FNM_EXTGLOB 0x10
89 #if CASEFOLD_FILESYSTEM
90 #define FNM_SYSCASE FNM_CASEFOLD
91 #else
92 #define FNM_SYSCASE 0
93 #endif
94
95 #define FNM_NOMATCH 1
96 #define FNM_ERROR 2
97
98 # define Next(p, e, enc) ((p)+ rb_enc_mbclen((p), (e), (enc)))
99 # define Inc(p, e, enc) ((p) = Next((p), (e), (enc)))
100
101 static char *
102 bracket(
103 const char *p, /* pattern (next to '[') */
104 const char *pend,
105 const char *s, /* string */
106 const char *send,
107 int flags,
108 rb_encoding *enc)
109 {
110 const int nocase = flags & FNM_CASEFOLD;
111 const int escape = !(flags & FNM_NOESCAPE);
112 unsigned int c1, c2;
113 int r;
114 int ok = 0, not = 0;
115
116 if (p >= pend) return NULL;
117 if (*p == '!' || *p == '^') {
118 not = 1;
119 p++;
120 }
121
122 while (*p != ']') {
123 const char *t1 = p;
124 if (escape && *t1 == '\\')
125 t1++;
126 if (!*t1)
127 return NULL;
128 p = t1 + (r = rb_enc_mbclen(t1, pend, enc));
129 if (p >= pend) return NULL;
130 if (p[0] == '-' && p[1] != ']') {
131 const char *t2 = p + 1;
132 int r2;
133 if (escape && *t2 == '\\')
134 t2++;
135 if (!*t2)
136 return NULL;
137 p = t2 + (r2 = rb_enc_mbclen(t2, pend, enc));
138 if (ok) continue;
139 if ((r <= (send-s) && memcmp(t1, s, r) == 0) ||
140 (r2 <= (send-s) && memcmp(t2, s, r2) == 0)) {
141 ok = 1;
142 continue;
143 }
144 c1 = rb_enc_codepoint(s, send, enc);
145 if (nocase) c1 = rb_enc_toupper(c1, enc);
146 c2 = rb_enc_codepoint(t1, pend, enc);
147 if (nocase) c2 = rb_enc_toupper(c2, enc);
148 if (c1 < c2) continue;
149 c2 = rb_enc_codepoint(t2, pend, enc);
150 if (nocase) c2 = rb_enc_toupper(c2, enc);
151 if (c1 > c2) continue;
152 }
153 else {
154 if (ok) continue;
155 if (r <= (send-s) && memcmp(t1, s, r) == 0) {
156 ok = 1;
157 continue;
158 }
159 if (!nocase) continue;
160 c1 = rb_enc_toupper(rb_enc_codepoint(s, send, enc), enc);
161 c2 = rb_enc_toupper(rb_enc_codepoint(p, pend, enc), enc);
162 if (c1 != c2) continue;
163 }
164 ok = 1;
165 }
166
167 return ok == not ? NULL : (char *)p + 1;
168 }
169
170 /* If FNM_PATHNAME is set, only path element will be matched. (upto '/' or '\0')
171 Otherwise, entire string will be matched.
172 End marker itself won't be compared.
173 And if function succeeds, *pcur reaches end marker.
174 */
175 #define UNESCAPE(p) (escape && *(p) == '\\' ? (p) + 1 : (p))
176 #define ISEND(p) (!*(p) || (pathname && *(p) == '/'))
177 #define RETURN(val) return *pcur = p, *scur = s, (val);
178
179 static int
180 fnmatch_helper(
181 const char **pcur, /* pattern */
182 const char **scur, /* string */
183 int flags,
184 rb_encoding *enc)
185 {
186 const int period = !(flags & FNM_DOTMATCH);
187 const int pathname = flags & FNM_PATHNAME;
188 const int escape = !(flags & FNM_NOESCAPE);
189 const int nocase = flags & FNM_CASEFOLD;
190
191 const char *ptmp = 0;
192 const char *stmp = 0;
193
194 const char *p = *pcur;
195 const char *pend = p + strlen(p);
196 const char *s = *scur;
197 const char *send = s + strlen(s);
198
199 int r;
200
201 if (period && *s == '.' && *UNESCAPE(p) != '.') /* leading period */
202 RETURN(FNM_NOMATCH);
203
204 while (1) {
205 switch (*p) {
206 case '*':
207 do { p++; } while (*p == '*');
208 if (ISEND(UNESCAPE(p))) {
209 p = UNESCAPE(p);
210 RETURN(0);
211 }
212 if (ISEND(s))
213 RETURN(FNM_NOMATCH);
214 ptmp = p;
215 stmp = s;
216 continue;
217
218 case '?':
219 if (ISEND(s))
220 RETURN(FNM_NOMATCH);
221 p++;
222 Inc(s, send, enc);
223 continue;
224
225 case '[': {
226 const char *t;
227 if (ISEND(s))
228 RETURN(FNM_NOMATCH);
229 if ((t = bracket(p + 1, pend, s, send, flags, enc)) != 0) {
230 p = t;
231 Inc(s, send, enc);
232 continue;
233 }
234 goto failed;
235 }
236 }
237
238 /* ordinary */
239 p = UNESCAPE(p);
240 if (ISEND(s))
241 RETURN(ISEND(p) ? 0 : FNM_NOMATCH);
242 if (ISEND(p))
243 goto failed;
244 r = rb_enc_precise_mbclen(p, pend, enc);
245 if (!MBCLEN_CHARFOUND_P(r))
246 goto failed;
247 if (r <= (send-s) && memcmp(p, s, r) == 0) {
248 p += r;
249 s += r;
250 continue;
251 }
252 if (!nocase) goto failed;
253 if (rb_enc_toupper(rb_enc_codepoint(p, pend, enc), enc) !=
254 rb_enc_toupper(rb_enc_codepoint(s, send, enc), enc))
255 goto failed;
256 p += r;
257 Inc(s, send, enc);
258 continue;
259
260 failed: /* try next '*' position */
261 if (ptmp && stmp) {
262 p = ptmp;
263 Inc(stmp, send, enc); /* !ISEND(*stmp) */
264 s = stmp;
265 continue;
266 }
267 RETURN(FNM_NOMATCH);
268 }
269 }
270
271 static int
272 fnmatch(
273 const char *pattern,
274 rb_encoding *enc,
275 const char *string,
276 int flags)
277 {
278 const char *p = pattern;
279 const char *s = string;
280 const char *send = s + strlen(string);
281 const int period = !(flags & FNM_DOTMATCH);
282 const int pathname = flags & FNM_PATHNAME;
283
284 const char *ptmp = 0;
285 const char *stmp = 0;
286
287 if (pathname) {
288 while (1) {
289 if (p[0] == '*' && p[1] == '*' && p[2] == '/') {
290 do { p += 3; } while (p[0] == '*' && p[1] == '*' && p[2] == '/');
291 ptmp = p;
292 stmp = s;
293 }
294 if (fnmatch_helper(&p, &s, flags, enc) == 0) {
295 while (*s && *s != '/') Inc(s, send, enc);
296 if (*p && *s) {
297 p++;
298 s++;
299 continue;
300 }
301 if (!*p && !*s)
302 return 0;
303 }
304 /* failed : try next recursion */
305 if (ptmp && stmp && !(period && *stmp == '.')) {
306 while (*stmp && *stmp != '/') Inc(stmp, send, enc);
307 if (*stmp) {
308 p = ptmp;
309 stmp++;
310 s = stmp;
311 continue;
312 }
313 }
314 return FNM_NOMATCH;
315 }
316 }
317 else
318 return fnmatch_helper(&p, &s, flags, enc);
319 }
320
321 VALUE rb_cDir;
322
323 struct dir_data {
324 DIR *dir;
325 VALUE path;
326 rb_encoding *enc;
327 };
328
329 static void
330 dir_mark(void *ptr)
331 {
332 struct dir_data *dir = ptr;
333 rb_gc_mark(dir->path);
334 }
335
336 static void
337 dir_free(void *ptr)
338 {
339 struct dir_data *dir = ptr;
340 if (dir) {
341 if (dir->dir) closedir(dir->dir);
342 }
343 xfree(dir);
344 }
345
346 static size_t
347 dir_memsize(const void *ptr)
348 {
349 return ptr ? sizeof(struct dir_data) : 0;
350 }
351
352 static const rb_data_type_t dir_data_type = {
353 "dir",
354 {dir_mark, dir_free, dir_memsize,},
355 };
356
357 static VALUE dir_close(VALUE);
358
359 #define GlobPathValue(str, safe) \
360 /* can contain null bytes as separators */ \
361 (!RB_TYPE_P((str), T_STRING) ? \
362 (void)FilePathValue(str) : \
363 (void)(check_safe_glob((str), (safe)), \
364 check_glob_encoding(str), (str)))
365 #define check_safe_glob(str, safe) ((safe) ? rb_check_safe_obj(str) : (void)0)
366 #define check_glob_encoding(str) rb_enc_check((str), rb_enc_from_encoding(rb_usascii_encoding()))
367
368 static VALUE
369 dir_s_alloc(VALUE klass)
370 {
371 struct dir_data *dirp;
372 VALUE obj = TypedData_Make_Struct(klass, struct dir_data, &dir_data_type, dirp);
373
374 dirp->dir = NULL;
375 dirp->path = Qnil;
376 dirp->enc = NULL;
377
378 return obj;
379 }
380
381 /*
382 * call-seq:
383 * Dir.new( string ) -> aDir
384 *
385 * Returns a new directory object for the named directory.
386 */
387 static VALUE
388 dir_initialize(int argc, VALUE *argv, VALUE dir)
389 {
390 struct dir_data *dp;
391 rb_encoding *fsenc;
392 VALUE dirname, opt, orig;
393 static VALUE sym_enc;
394
395 if (!sym_enc) {
396 sym_enc = ID2SYM(rb_intern("encoding"));
397 }
398 fsenc = rb_filesystem_encoding();
399
400 rb_scan_args(argc, argv, "1:", &dirname, &opt);
401
402 if (!NIL_P(opt)) {
403 VALUE enc = rb_hash_aref(opt, sym_enc);
404 if (!NIL_P(enc)) {
405 fsenc = rb_to_encoding(enc);
406 }
407 }
408
409 GlobPathValue(dirname, FALSE);
410 orig = rb_str_dup_frozen(dirname);
411 dirname = rb_str_encode_ospath(dirname);
412 dirname = rb_str_dup_frozen(dirname);
413
414 TypedData_Get_Struct(dir, struct dir_data, &dir_data_type, dp);
415 if (dp->dir) closedir(dp->dir);
416 dp->dir = NULL;
417 dp->path = Qnil;
418 dp->enc = fsenc;
419 dp->dir = opendir(RSTRING_PTR(dirname));
420 if (dp->dir == NULL) {
421 if (errno == EMFILE || errno == ENFILE) {
422 rb_gc();
423 dp->dir = opendir(RSTRING_PTR(dirname));
424 }
425 if (dp->dir == NULL) {
426 rb_sys_fail_path(orig);
427 }
428 }
429 dp->path = orig;
430
431 return dir;
432 }
433
434 /*
435 * call-seq:
436 * Dir.open( string ) -> aDir
437 * Dir.open( string ) {| aDir | block } -> anObject
438 *
439 * With no block, <code>open</code> is a synonym for
440 * <code>Dir::new</code>. If a block is present, it is passed
441 * <i>aDir</i> as a parameter. The directory is closed at the end of
442 * the block, and <code>Dir::open</code> returns the value of the
443 * block.
444 */
445 static VALUE
446 dir_s_open(int argc, VALUE *argv, VALUE klass)
447 {
448 struct dir_data *dp;
449 VALUE dir = TypedData_Make_Struct(klass, struct dir_data, &dir_data_type, dp);
450
451 dir_initialize(argc, argv, dir);
452 if (rb_block_given_p()) {
453 return rb_ensure(rb_yield, dir, dir_close, dir);
454 }
455
456 return dir;
457 }
458
459 static void
460 dir_closed(void)
461 {
462 rb_raise(rb_eIOError, "closed directory");
463 }
464
465 static struct dir_data *
466 dir_check(VALUE dir)
467 {
468 struct dir_data *dirp;
469 if (!OBJ_UNTRUSTED(dir) && rb_safe_level() >= 4)
470 rb_raise(rb_eSecurityError, "Insecure: operation on trusted Dir");
471 rb_check_frozen(dir);
472 dirp = rb_check_typeddata(dir, &dir_data_type);
473 if (!dirp->dir) dir_closed();
474 return dirp;
475 }
476
477 #define GetDIR(obj, dirp) ((dirp) = dir_check(obj))
478
479
480 /*
481 * call-seq:
482 * dir.inspect -> string
483 *
484 * Return a string describing this Dir object.
485 */
486 static VALUE
487 dir_inspect(VALUE dir)
488 {
489 struct dir_data *dirp;
490
491 TypedData_Get_Struct(dir, struct dir_data, &dir_data_type, dirp);
492 if (!NIL_P(dirp->path)) {
493 VALUE str = rb_str_new_cstr("#<");
494 rb_str_append(str, rb_class_name(CLASS_OF(dir)));
495 rb_str_cat2(str, ":");
496 rb_str_append(str, dirp->path);
497 rb_str_cat2(str, ">");
498 return str;
499 }
500 return rb_funcall(dir, rb_intern("to_s"), 0, 0);
501 }
502
503 /*
504 * call-seq:
505 * dir.path -> string or nil
506 *
507 * Returns the path parameter passed to <em>dir</em>'s constructor.
508 *
509 * d = Dir.new("..")
510 * d.path #=> ".."
511 */
512 static VALUE
513 dir_path(VALUE dir)
514 {
515 struct dir_data *dirp;
516
517 TypedData_Get_Struct(dir, struct dir_data, &dir_data_type, dirp);
518 if (NIL_P(dirp->path)) return Qnil;
519 return rb_str_dup(dirp->path);
520 }
521
522 #if defined HAVE_READDIR_R
523 # define READDIR(dir, enc, entry, dp) (readdir_r((dir), (entry), &(dp)) == 0 && (dp) != 0)
524 #elif defined _WIN32
525 # define READDIR(dir, enc, entry, dp) (((dp) = rb_w32_readdir((dir), (enc))) != 0)
526 #else
527 # define READDIR(dir, enc, entry, dp) (((dp) = readdir(dir)) != 0)
528 #endif
529 #if defined HAVE_READDIR_R
530 # define IF_HAVE_READDIR_R(something) something
531 #else
532 # define IF_HAVE_READDIR_R(something) /* nothing */
533 #endif
534
535 #if defined SIZEOF_STRUCT_DIRENT_TOO_SMALL
536 # include <limits.h>
537 # define NAME_MAX_FOR_STRUCT_DIRENT 255
538 # if defined NAME_MAX
539 # if NAME_MAX_FOR_STRUCT_DIRENT < NAME_MAX
540 # undef NAME_MAX_FOR_STRUCT_DIRENT
541 # define NAME_MAX_FOR_STRUCT_DIRENT NAME_MAX
542 # endif
543 # endif
544 # if defined _POSIX_NAME_MAX
545 # if NAME_MAX_FOR_STRUCT_DIRENT < _POSIX_NAME_MAX
546 # undef NAME_MAX_FOR_STRUCT_DIRENT
547 # define NAME_MAX_FOR_STRUCT_DIRENT _POSIX_NAME_MAX
548 # endif
549 # endif
550 # if defined _XOPEN_NAME_MAX
551 # if NAME_MAX_FOR_STRUCT_DIRENT < _XOPEN_NAME_MAX
552 # undef NAME_MAX_FOR_STRUCT_DIRENT
553 # define NAME_MAX_FOR_STRUCT_DIRENT _XOPEN_NAME_MAX
554 # endif
555 # endif
556 # define DEFINE_STRUCT_DIRENT \
557 union { \
558 struct dirent dirent; \
559 char dummy[offsetof(struct dirent, d_name) + \
560 NAME_MAX_FOR_STRUCT_DIRENT + 1]; \
561 }
562 # define STRUCT_DIRENT(entry) ((entry).dirent)
563 #else
564 # define DEFINE_STRUCT_DIRENT struct dirent
565 # define STRUCT_DIRENT(entry) (entry)
566 #endif
567
568 /*
569 * call-seq:
570 * dir.read -> string or nil
571 *
572 * Reads the next entry from <em>dir</em> and returns it as a string.
573 * Returns <code>nil</code> at the end of the stream.
574 *
575 * d = Dir.new("testdir")
576 * d.read #=> "."
577 * d.read #=> ".."
578 * d.read #=> "config.h"
579 */
580 static VALUE
581 dir_read(VALUE dir)
582 {
583 struct dir_data *dirp;
584 struct dirent *dp;
585 IF_HAVE_READDIR_R(DEFINE_STRUCT_DIRENT entry);
586
587 GetDIR(dir, dirp);
588 errno = 0;
589 if (READDIR(dirp->dir, dirp->enc, &STRUCT_DIRENT(entry), dp)) {
590 return rb_external_str_new_with_enc(dp->d_name, NAMLEN(dp), dirp->enc);
591 }
592 else {
593 if (errno != 0) rb_sys_fail(0);
594 return Qnil; /* end of stream */
595 }
596 }
597
598 /*
599 * call-seq:
600 * dir.each { |filename| block } -> dir
601 * dir.each -> an_enumerator
602 *
603 * Calls the block once for each entry in this directory, passing the
604 * filename of each entry as a parameter to the block.
605 *
606 * If no block is given, an enumerator is returned instead.
607 *
608 * d = Dir.new("testdir")
609 * d.each {|x| puts "Got #{x}" }
610 *
611 * <em>produces:</em>
612 *
613 * Got .
614 * Got ..
615 * Got config.h
616 * Got main.rb
617 */
618 static VALUE
619 dir_each(VALUE dir)
620 {
621 struct dir_data *dirp;
622 struct dirent *dp;
623 IF_HAVE_READDIR_R(DEFINE_STRUCT_DIRENT entry);
624
625 RETURN_ENUMERATOR(dir, 0, 0);
626 GetDIR(dir, dirp);
627 rewinddir(dirp->dir);
628 while (READDIR(dirp->dir, dirp->enc, &STRUCT_DIRENT(entry), dp)) {
629 rb_yield(rb_external_str_new_with_enc(dp->d_name, NAMLEN(dp), dirp->enc));
630 if (dirp->dir == NULL) dir_closed();
631 }
632 return dir;
633 }
634
635 #ifdef HAVE_TELLDIR
636 /*
637 * call-seq:
638 * dir.pos -> integer
639 * dir.tell -> integer
640 *
641 * Returns the current position in <em>dir</em>. See also
642 * <code>Dir#seek</code>.
643 *
644 * d = Dir.new("testdir")
645 * d.tell #=> 0
646 * d.read #=> "."
647 * d.tell #=> 12
648 */
649 static VALUE
650 dir_tell(VALUE dir)
651 {
652 struct dir_data *dirp;
653 long pos;
654
655 GetDIR(dir, dirp);
656 pos = telldir(dirp->dir);
657 return rb_int2inum(pos);
658 }
659 #else
660 #define dir_tell rb_f_notimplement
661 #endif
662
663 #ifdef HAVE_SEEKDIR
664 /*
665 * call-seq:
666 * dir.seek( integer ) -> dir
667 *
668 * Seeks to a particular location in <em>dir</em>. <i>integer</i>
669 * must be a value returned by <code>Dir#tell</code>.
670 *
671 * d = Dir.new("testdir") #=> #<Dir:0x401b3c40>
672 * d.read #=> "."
673 * i = d.tell #=> 12
674 * d.read #=> ".."
675 * d.seek(i) #=> #<Dir:0x401b3c40>
676 * d.read #=> ".."
677 */
678 static VALUE
679 dir_seek(VALUE dir, VALUE pos)
680 {
681 struct dir_data *dirp;
682 long p = NUM2LONG(pos);
683
684 GetDIR(dir, dirp);
685 seekdir(dirp->dir, p);
686 return dir;
687 }
688 #else
689 #define dir_seek rb_f_notimplement
690 #endif
691
692 #ifdef HAVE_SEEKDIR
693 /*
694 * call-seq:
695 * dir.pos( integer ) -> integer
696 *
697 * Synonym for <code>Dir#seek</code>, but returns the position
698 * parameter.
699 *
700 * d = Dir.new("testdir") #=> #<Dir:0x401b3c40>
701 * d.read #=> "."
702 * i = d.pos #=> 12
703 * d.read #=> ".."
704 * d.pos = i #=> 12
705 * d.read #=> ".."
706 */
707 static VALUE
708 dir_set_pos(VALUE dir, VALUE pos)
709 {
710 dir_seek(dir, pos);
711 return pos;
712 }
713 #else
714 #define dir_set_pos rb_f_notimplement
715 #endif
716
717 /*
718 * call-seq:
719 * dir.rewind -> dir
720 *
721 * Repositions <em>dir</em> to the first entry.
722 *
723 * d = Dir.new("testdir")
724 * d.read #=> "."
725 * d.rewind #=> #<Dir:0x401b3fb0>
726 * d.read #=> "."
727 */
728 static VALUE
729 dir_rewind(VALUE dir)
730 {
731 struct dir_data *dirp;
732
733 if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(dir)) {
734 rb_raise(rb_eSecurityError, "Insecure: can't close");
735 }
736 GetDIR(dir, dirp);
737 rewinddir(dirp->dir);
738 return dir;
739 }
740
741 /*
742 * call-seq:
743 * dir.close -> nil
744 *
745 * Closes the directory stream. Any further attempts to access
746 * <em>dir</em> will raise an <code>IOError</code>.
747 *
748 * d = Dir.new("testdir")
749 * d.close #=> nil
750 */
751 static VALUE
752 dir_close(VALUE dir)
753 {
754 struct dir_data *dirp;
755
756 GetDIR(dir, dirp);
757 closedir(dirp->dir);
758 dirp->dir = NULL;
759
760 return Qnil;
761 }
762
763 static void
764 dir_chdir(VALUE path)
765 {
766 if (chdir(RSTRING_PTR(path)) < 0)
767 rb_sys_fail_path(path);
768 }
769
770 static int chdir_blocking = 0;
771 static VALUE chdir_thread = Qnil;
772
773 struct chdir_data {
774 VALUE old_path, new_path;
775 int done;
776 };
777
778 static VALUE
779 chdir_yield(struct chdir_data *args)
780 {
781 dir_chdir(args->new_path);
782 args->done = TRUE;
783 chdir_blocking++;
784 if (chdir_thread == Qnil)
785 chdir_thread = rb_thread_current();
786 return rb_yield(args->new_path);
787 }
788
789 static VALUE
790 chdir_restore(struct chdir_data *args)
791 {
792 if (args->done) {
793 chdir_blocking--;
794 if (chdir_blocking == 0)
795 chdir_thread = Qnil;
796 dir_chdir(args->old_path);
797 }
798 return Qnil;
799 }
800
801 /*
802 * call-seq:
803 * Dir.chdir( [ string] ) -> 0
804 * Dir.chdir( [ string] ) {| path | block } -> anObject
805 *
806 * Changes the current working directory of the process to the given
807 * string. When called without an argument, changes the directory to
808 * the value of the environment variable <code>HOME</code>, or
809 * <code>LOGDIR</code>. <code>SystemCallError</code> (probably
810 * <code>Errno::ENOENT</code>) if the target directory does not exist.
811 *
812 * If a block is given, it is passed the name of the new current
813 * directory, and the block is executed with that as the current
814 * directory. The original working directory is restored when the block
815 * exits. The return value of <code>chdir</code> is the value of the
816 * block. <code>chdir</code> blocks can be nested, but in a
817 * multi-threaded program an error will be raised if a thread attempts
818 * to open a <code>chdir</code> block while another thread has one
819 * open.
820 *
821 * Dir.chdir("/var/spool/mail")
822 * puts Dir.pwd
823 * Dir.chdir("/tmp") do
824 * puts Dir.pwd
825 * Dir.chdir("/usr") do
826 * puts Dir.pwd
827 * end
828 * puts Dir.pwd
829 * end
830 * puts Dir.pwd
831 *
832 * <em>produces:</em>
833 *
834 * /var/spool/mail
835 * /tmp
836 * /usr
837 * /tmp
838 * /var/spool/mail
839 */
840 static VALUE
841 dir_s_chdir(int argc, VALUE *argv, VALUE obj)
842 {
843 VALUE path = Qnil;
844
845 rb_secure(2);
846 if (rb_scan_args(argc, argv, "01", &path) == 1) {
847 FilePathValue(path);
848 path = rb_str_encode_ospath(path);
849 }
850 else {
851 const char *dist = getenv("HOME");
852 if (!dist) {
853 dist = getenv("LOGDIR");
854 if (!dist) rb_raise(rb_eArgError, "HOME/LOGDIR not set");
855 }
856 path = rb_str_new2(dist);
857 }
858
859 if (chdir_blocking > 0) {
860 if (!rb_block_given_p() || rb_thread_current() != chdir_thread)
861 rb_warn("conflicting chdir during another chdir block");
862 }
863
864 if (rb_block_given_p()) {
865 struct chdir_data args;
866
867 args.old_path = rb_str_encode_ospath(rb_dir_getwd());
868 args.new_path = path;
869 args.done = FALSE;
870 return rb_ensure(chdir_yield, (VALUE)&args, chdir_restore, (VALUE)&args);
871 }
872 dir_chdir(path);
873
874 return INT2FIX(0);
875 }
876
877 VALUE
878 rb_dir_getwd(void)
879 {
880 char *path;
881 VALUE cwd;
882
883 rb_secure(4);
884 path = my_getcwd();
885 cwd = rb_tainted_str_new2(path);
886 rb_enc_associate(cwd, rb_filesystem_encoding());
887
888 xfree(path);
889 return cwd;
890 }
891
892 /*
893 * call-seq:
894 * Dir.getwd -> string
895 * Dir.pwd -> string
896 *
897 * Returns the path to the current working directory of this process as
898 * a string.
899 *
900 * Dir.chdir("/tmp") #=> 0
901 * Dir.getwd #=> "/tmp"
902 */
903 static VALUE
904 dir_s_getwd(VALUE dir)
905 {
906 return rb_dir_getwd();
907 }
908
909 static void
910 check_dirname(volatile VALUE *dir)
911 {
912 VALUE d = *dir;
913 char *path, *pend;
914 long len;
915 rb_encoding *enc;
916
917 rb_secure(2);
918 FilePathValue(d);
919 enc = rb_enc_get(d);
920 RSTRING_GETMEM(d, path, len);
921 pend = path + len;
922 pend = rb_enc_path_end(rb_enc_path_skip_prefix(path, pend, enc), pend, enc);
923 if (pend - path < len) {
924 d = rb_str_subseq(d, 0, pend - path);
925 }
926 *dir = rb_str_encode_ospath(d);
927 }
928
929 #if defined(HAVE_CHROOT)
930 /*
931 * call-seq:
932 * Dir.chroot( string ) -> 0
933 *
934 * Changes this process's idea of the file system root. Only a
935 * privileged process may make this call. Not available on all
936 * platforms. On Unix systems, see <code>chroot(2)</code> for more
937 * information.
938 */
939 static VALUE
940 dir_s_chroot(VALUE dir, VALUE path)
941 {
942 check_dirname(&path);
943 if (chroot(RSTRING_PTR(path)) == -1)
944 rb_sys_fail_path(path);
945
946 return INT2FIX(0);
947 }
948 #else
949 #define dir_s_chroot rb_f_notimplement
950 #endif
951
952 /*
953 * call-seq:
954 * Dir.mkdir( string [, integer] ) -> 0
955 *
956 * Makes a new directory named by <i>string</i>, with permissions
957 * specified by the optional parameter <i>anInteger</i>. The
958 * permissions may be modified by the value of
959 * <code>File::umask</code>, and are ignored on NT. Raises a
960 * <code>SystemCallError</code> if the directory cannot be created. See
961 * also the discussion of permissions in the class documentation for
962 * <code>File</code>.
963 *
964 * Dir.mkdir(File.join(Dir.home, ".foo"), 0700) #=> 0
965 *
966 */
967 static VALUE
968 dir_s_mkdir(int argc, VALUE *argv, VALUE obj)
969 {
970 VALUE path, vmode;
971 int mode;
972
973 if (rb_scan_args(argc, argv, "11", &path, &vmode) == 2) {
974 mode = NUM2INT(vmode);
975 }
976 else {
977 mode = 0777;
978 }
979
980 check_dirname(&path);
981 if (mkdir(RSTRING_PTR(path), mode) == -1)
982 rb_sys_fail_path(path);
983
984 return INT2FIX(0);
985 }
986
987 /*
988 * call-seq:
989 * Dir.delete( string ) -> 0
990 * Dir.rmdir( string ) -> 0
991 * Dir.unlink( string ) -> 0
992 *
993 * Deletes the named directory. Raises a subclass of
994 * <code>SystemCallError</code> if the directory isn't empty.
995 */
996 static VALUE
997 dir_s_rmdir(VALUE obj, VALUE dir)
998 {
999 check_dirname(&dir);
1000 if (rmdir(RSTRING_PTR(dir)) < 0)
1001 rb_sys_fail_path(dir);
1002
1003 return INT2FIX(0);
1004 }
1005
1006 static VALUE
1007 sys_warning_1(VALUE mesg)
1008 {
1009 rb_sys_warning("%s:%s", strerror(errno), (const char *)mesg);
1010 return Qnil;
1011 }
1012
1013 #define GLOB_VERBOSE (1U << (sizeof(int) * CHAR_BIT - 1))
1014 #define sys_warning(val) \
1015 (void)((flags & GLOB_VERBOSE) && rb_protect(sys_warning_1, (VALUE)(val), 0))
1016
1017 #define GLOB_ALLOC(type) ((type *)malloc(sizeof(type)))
1018 #define GLOB_ALLOC_N(type, n) ((type *)malloc(sizeof(type) * (n)))
1019 #define GLOB_FREE(ptr) free(ptr)
1020 #define GLOB_JUMP_TAG(status) (((status) == -1) ? rb_memerror() : rb_jump_tag(status))
1021
1022 /*
1023 * ENOTDIR can be returned by stat(2) if a non-leaf element of the path
1024 * is not a directory.
1025 */
1026 #define to_be_ignored(e) ((e) == ENOENT || (e) == ENOTDIR)
1027
1028 /* System call with warning */
1029 static int
1030 do_stat(const char *path, struct stat *pst, int flags)
1031
1032 {
1033 int ret = stat(path, pst);
1034 if (ret < 0 && !to_be_ignored(errno))
1035 sys_warning(path);
1036
1037 return ret;
1038 }
1039
1040 static int
1041 do_lstat(const char *path, struct stat *pst, int flags)
1042 {
1043 int ret = lstat(path, pst);
1044 if (ret < 0 && !to_be_ignored(errno))
1045 sys_warning(path);
1046
1047 return ret;
1048 }
1049
1050 static DIR *
1051 do_opendir(const char *path, int flags, rb_encoding *enc)
1052 {
1053 DIR *dirp;
1054 #ifdef _WIN32
1055 volatile VALUE tmp;
1056 if (enc != rb_usascii_encoding() &&
1057 enc != rb_ascii8bit_encoding() &&
1058 enc != rb_utf8_encoding()) {
1059 tmp = rb_enc_str_new(path, strlen(path), enc);
1060 tmp = rb_str_encode_ospath(tmp);
1061 path = RSTRING_PTR(tmp);
1062 }
1063 #endif
1064 dirp = opendir(path);
1065 if (dirp == NULL && !to_be_ignored(errno))
1066 sys_warning(path);
1067
1068 return dirp;
1069 }
1070
1071 /* Return nonzero if S has any special globbing chars in it. */
1072 static int
1073 has_magic(const char *p, const char *pend, int flags, rb_encoding *enc)
1074 {
1075 const int escape = !(flags & FNM_NOESCAPE);
1076 const int nocase = flags & FNM_CASEFOLD;
1077
1078 register char c;
1079
1080 while (p < pend && (c = *p++) != 0) {
1081 switch (c) {
1082 case '*':
1083 case '?':
1084 case '[':
1085 return 1;
1086
1087 case '\\':
1088 if (escape && !(c = *p++))
1089 return 0;
1090 continue;
1091
1092 default:
1093 if (!FNM_SYSCASE && ISALPHA(c) && nocase)
1094 return 1;
1095 }
1096
1097 p = Next(p-1, pend, enc);
1098 }
1099
1100 return 0;
1101 }
1102
1103 /* Find separator in globbing pattern. */
1104 static char *
1105 find_dirsep(const char *p, const char *pend, int flags, rb_encoding *enc)
1106 {
1107 const int escape = !(flags & FNM_NOESCAPE);
1108
1109 register char c;
1110 int open = 0;
1111
1112 while ((c = *p++) != 0) {
1113 switch (c) {
1114 case '[':
1115 open = 1;
1116 continue;
1117 case ']':
1118 open = 0;
1119 continue;
1120
1121 case '/':
1122 if (!open)
1123 return (char *)p-1;
1124 continue;
1125
1126 case '\\':
1127 if (escape && !(c = *p++))
1128 return (char *)p-1;
1129 continue;
1130 }
1131
1132 p = Next(p-1, pend, enc);
1133 }
1134
1135 return (char *)p-1;
1136 }
1137
1138 /* Remove escaping backslashes */
1139 static char *
1140 remove_backslashes(char *p, register const char *pend, rb_encoding *enc)
1141 {
1142 char *t = p;
1143 char *s = p;
1144
1145 while (*p) {
1146 if (*p == '\\') {
1147 if (t != s)
1148 memmove(t, s, p - s);
1149 t += p - s;
1150 s = ++p;
1151 if (!*p) break;
1152 }
1153 Inc(p, pend, enc);
1154 }
1155
1156 while (*p++);
1157
1158 if (t != s)
1159 memmove(t, s, p - s); /* move '\0' too */
1160
1161 return p;
1162 }
1163
1164 /* Globing pattern */
1165 enum glob_pattern_type { PLAIN, MAGICAL, RECURSIVE, MATCH_ALL, MATCH_DIR };
1166
1167 struct glob_pattern {
1168 char *str;
1169 enum glob_pattern_type type;
1170 struct glob_pattern *next;
1171 };
1172
1173 static void glob_free_pattern(struct glob_pattern *list);
1174
1175 static struct glob_pattern *
1176 glob_make_pattern(const char *p, const char *e, int flags, rb_encoding *enc)
1177 {
1178 struct glob_pattern *list, *tmp, **tail = &list;
1179 int dirsep = 0; /* pattern is terminated with '/' */
1180 int recursive = 0;
1181
1182 while (p < e && *p) {
1183 tmp = GLOB_ALLOC(struct glob_pattern);
1184 if (!tmp) goto error;
1185 if (p[0] == '*' && p[1] == '*' && p[2] == '/') {
1186 /* fold continuous RECURSIVEs (needed in glob_helper) */
1187 do { p += 3; while (*p == '/') p++; } while (p[0] == '*' && p[1] == '*' && p[2] == '/');
1188 tmp->type = RECURSIVE;
1189 tmp->str = 0;
1190 dirsep = 1;
1191 recursive = 1;
1192 }
1193 else {
1194 const char *m = find_dirsep(p, e, flags, enc);
1195 int magic = has_magic(p, m, flags, enc);
1196 char *buf;
1197
1198 if (!magic && !recursive && *m) {
1199 const char *m2;
1200 while (!has_magic(m+1, m2 = find_dirsep(m+1, e, flags, enc), flags, enc) &&
1201 *m2) {
1202 m = m2;
1203 }
1204 }
1205 buf = GLOB_ALLOC_N(char, m-p+1);
1206 if (!buf) {
1207 GLOB_FREE(tmp);
1208 goto error;
1209 }
1210 memcpy(buf, p, m-p);
1211 buf[m-p] = '\0';
1212 tmp->type = magic ? MAGICAL : PLAIN;
1213 tmp->str = buf;
1214 if (*m) {
1215 dirsep = 1;
1216 p = m + 1;
1217 }
1218 else {
1219 dirsep = 0;
1220 p = m;
1221 }
1222 }
1223 *tail = tmp;
1224 tail = &tmp->next;
1225 }
1226
1227 tmp = GLOB_ALLOC(struct glob_pattern);
1228 if (!tmp) {
1229 error:
1230 *tail = 0;
1231 glob_free_pattern(list);
1232 return 0;
1233 }
1234 tmp->type = dirsep ? MATCH_DIR : MATCH_ALL;
1235 tmp->str = 0;
1236 *tail = tmp;
1237 tmp->next = 0;
1238
1239 return list;
1240 }
1241
1242 static void
1243 glob_free_pattern(struct glob_pattern *list)
1244 {
1245 while (list) {
1246 struct glob_pattern *tmp = list;
1247 list = list->next;
1248 if (tmp->str)
1249 GLOB_FREE(tmp->str);
1250 GLOB_FREE(tmp);
1251 }
1252 }
1253
1254 static char *
1255 join_path(const char *path, int dirsep, const char *name, size_t namlen)
1256 {
1257 long len = strlen(path);
1258 char *buf = GLOB_ALLOC_N(char, len+namlen+(dirsep?1:0)+1);
1259
1260 if (!buf) return 0;
1261 memcpy(buf, path, len);
1262 if (dirsep) {
1263 buf[len++] = '/';
1264 }
1265 memcpy(buf+len, name, namlen);
1266 buf[len+namlen] = '\0';
1267 return buf;
1268 }
1269
1270 enum answer {UNKNOWN = -1, NO, YES};
1271
1272 #ifndef S_ISDIR
1273 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
1274 #endif
1275
1276 #ifndef S_ISLNK
1277 # ifndef S_IFLNK
1278 # define S_ISLNK(m) (0)
1279 # else
1280 # define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
1281 # endif
1282 #endif
1283
1284 struct glob_args {
1285 void (*func)(const char *, VALUE, void *);
1286 const char *path;
1287 VALUE value;
1288 rb_encoding *enc;
1289 };
1290
1291 static VALUE
1292 glob_func_caller(VALUE val)
1293 {
1294 struct glob_args *args = (struct glob_args *)val;
1295
1296 (*args->func)(args->path, args->value, args->enc);
1297 return Qnil;
1298 }
1299
1300 #define glob_call_func(func, path, arg, enc) (*(func))((path), (arg), (enc))
1301
1302 static int
1303 glob_helper(
1304 const char *path,
1305 int dirsep, /* '/' should be placed before appending child entry's name to 'path'. */
1306 enum answer exist, /* Does 'path' indicate an existing entry? */
1307 enum answer isdir, /* Does 'path' indicate a directory or a symlink to a directory? */
1308 struct glob_pattern **beg,
1309 struct glob_pattern **end,
1310 int flags,
1311 ruby_glob_func *func,
1312 VALUE arg,
1313 rb_encoding *enc)
1314 {
1315 struct stat st;
1316 int status = 0;
1317 struct glob_pattern **cur, **new_beg, **new_end;
1318 int plain = 0, magical = 0, recursive = 0, match_all = 0, match_dir = 0;
1319 int escape = !(flags & FNM_NOESCAPE);
1320
1321 for (cur = beg; cur < end; ++cur) {
1322 struct glob_pattern *p = *cur;
1323 if (p->type == RECURSIVE) {
1324 recursive = 1;
1325 p = p->next;
1326 }
1327 switch (p->type) {
1328 case PLAIN:
1329 plain = 1;
1330 break;
1331 case MAGICAL:
1332 magical = 1;
1333 break;
1334 case MATCH_ALL:
1335 match_all = 1;
1336 break;
1337 case MATCH_DIR:
1338 match_dir = 1;
1339 break;
1340 case RECURSIVE:
1341 rb_bug("continuous RECURSIVEs");
1342 }
1343 }
1344
1345 if (*path) {
1346 if (match_all && exist == UNKNOWN) {
1347 if (do_lstat(path, &st, flags) == 0) {
1348 exist = YES;
1349 isdir = S_ISDIR(st.st_mode) ? YES : S_ISLNK(st.st_mode) ? UNKNOWN : NO;
1350 }
1351 else {
1352 exist = NO;
1353 isdir = NO;
1354 }
1355 }
1356 if (match_dir && isdir == UNKNOWN) {
1357 if (do_stat(path, &st, flags) == 0) {
1358 exist = YES;
1359 isdir = S_ISDIR(st.st_mode) ? YES : NO;
1360 }
1361 else {
1362 exist = NO;
1363 isdir = NO;
1364 }
1365 }
1366 if (match_all && exist == YES) {
1367 status = glob_call_func(func, path, arg, enc);
1368 if (status) return status;
1369 }
1370 if (match_dir && isdir == YES) {
1371 char *tmp = join_path(path, dirsep, "", 0);
1372 if (!tmp) return -1;
1373 status = glob_call_func(func, tmp, arg, enc);
1374 GLOB_FREE(tmp);
1375 if (status) return status;
1376 }
1377 }
1378
1379 if (exist == NO || isdir == NO) return 0;
1380
1381 if (magical || recursive) {
1382 struct dirent *dp;
1383 DIR *dirp;
1384 IF_HAVE_READDIR_R(DEFINE_STRUCT_DIRENT entry);
1385 dirp = do_opendir(*path ? path : ".", flags, enc);
1386 if (dirp == NULL) return 0;
1387
1388 while (READDIR(dirp, enc, &STRUCT_DIRENT(entry), dp)) {
1389 char *buf;
1390 enum answer new_isdir = UNKNOWN;
1391
1392 if (recursive && dp->d_name[0] == '.') {
1393 /* always skip current and parent directories not to recurse infinitely */
1394 if (!dp->d_name[1]) continue;
1395 if (dp->d_name[1] == '.' && !dp->d_name[2]) continue;
1396 }
1397
1398 buf = join_path(path, dirsep, dp->d_name, NAMLEN(dp));
1399 if (!buf) {
1400 status = -1;
1401 break;
1402 }
1403 if (recursive && ((flags & FNM_DOTMATCH) || dp->d_name[0] != '.')) {
1404 /* RECURSIVE never match dot files unless FNM_DOTMATCH is set */
1405 #ifndef _WIN32
1406 if (do_lstat(buf, &st, flags) == 0)
1407 new_isdir = S_ISDIR(st.st_mode) ? YES : S_ISLNK(st.st_mode) ? UNKNOWN : NO;
1408 else
1409 new_isdir = NO;
1410 #else
1411 new_isdir = dp->d_isdir ? (!dp->d_isrep ? YES : UNKNOWN) : NO;
1412 #endif
1413 }
1414
1415 new_beg = new_end = GLOB_ALLOC_N(struct glob_pattern *, (end - beg) * 2);
1416 if (!new_beg) {
1417 GLOB_FREE(buf);
1418 status = -1;
1419 break;
1420 }
1421
1422 for (cur = beg; cur < end; ++cur) {
1423 struct glob_pattern *p = *cur;
1424 if (p->type == RECURSIVE) {
1425 if (new_isdir == YES) /* not symlink but real directory */
1426 *new_end++ = p; /* append recursive pattern */
1427 p = p->next; /* 0 times recursion */
1428 }
1429 if (p->type == PLAIN || p->type == MAGICAL) {
1430 if (fnmatch(p->str, enc, dp->d_name, flags) == 0)
1431 *new_end++ = p->next;
1432 }
1433 }
1434
1435 status = glob_helper(buf, 1, YES, new_isdir, new_beg, new_end,
1436 flags, func, arg, enc);
1437 GLOB_FREE(buf);
1438 GLOB_FREE(new_beg);
1439 if (status) break;
1440 }
1441
1442 closedir(dirp);
1443 }
1444 else if (plain) {
1445 struct glob_pattern **copy_beg, **copy_end, **cur2;
1446
1447 copy_beg = copy_end = GLOB_ALLOC_N(struct glob_pattern *, end - beg);
1448 if (!copy_beg) return -1;
1449 for (cur = beg; cur < end; ++cur)
1450 *copy_end++ = (*cur)->type == PLAIN ? *cur : 0;
1451
1452 for (cur = copy_beg; cur < copy_end; ++cur) {
1453 if (*cur) {
1454 char *buf;
1455 char *name;
1456 size_t len = strlen((*cur)->str) + 1;
1457 name = GLOB_ALLOC_N(char, len);
1458 if (!name) {
1459 status = -1;
1460 break;
1461 }
1462 memcpy(name, (*cur)->str, len);
1463 if (escape)
1464 len = remove_backslashes(name, name+len-1, enc) - name;
1465
1466 new_beg = new_end = GLOB_ALLOC_N(struct glob_pattern *, end - beg);
1467 if (!new_beg) {
1468 GLOB_FREE(name);
1469 status = -1;
1470 break;
1471 }
1472 *new_end++ = (*cur)->next;
1473 for (cur2 = cur + 1; cur2 < copy_end; ++cur2) {
1474 if (*cur2 && fnmatch((*cur2)->str, enc, name, flags) == 0) {
1475 *new_end++ = (*cur2)->next;
1476 *cur2 = 0;
1477 }
1478 }
1479
1480 buf = join_path(path, dirsep, name, len);
1481 GLOB_FREE(name);
1482 if (!buf) {
1483 GLOB_FREE(new_beg);
1484 status = -1;
1485 break;
1486 }
1487 status = glob_helper(buf, 1, UNKNOWN, UNKNOWN, new_beg,
1488 new_end, flags, func, arg, enc);
1489 GLOB_FREE(buf);
1490 GLOB_FREE(new_beg);
1491 if (status) break;
1492 }
1493 }
1494
1495 GLOB_FREE(copy_beg);
1496 }
1497
1498 return status;
1499 }
1500
1501 static int
1502 ruby_glob0(const char *path, int flags, ruby_glob_func *func, VALUE arg, rb_encoding *enc)
1503 {
1504 struct glob_pattern *list;
1505 const char *root, *start;
1506 char *buf;
1507 size_t n;
1508 int status;
1509
1510 start = root = path;
1511 flags |= FNM_SYSCASE;
1512 #if defined DOSISH
1513 root = rb_enc_path_skip_prefix(root, root + strlen(root), enc);
1514 #endif
1515
1516 if (root && *root == '/') root++;
1517
1518 n = root - start;
1519 buf = GLOB_ALLOC_N(char, n + 1);
1520 if (!buf) return -1;
1521 MEMCPY(buf, start, char, n);
1522 buf[n] = '\0';
1523
1524 list = glob_make_pattern(root, root + strlen(root), flags, enc);
1525 if (!list) {
1526 GLOB_FREE(buf);
1527 return -1;
1528 }
1529 status = glob_helper(buf, 0, UNKNOWN, UNKNOWN, &list, &list + 1, flags, func, arg, enc);
1530 glob_free_pattern(list);
1531 GLOB_FREE(buf);
1532
1533 return status;
1534 }
1535
1536 int
1537 ruby_glob(const char *path, int flags, ruby_glob_func *func, VALUE arg)
1538 {
1539 return ruby_glob0(path, flags & ~GLOB_VERBOSE, func, arg,
1540 rb_ascii8bit_encoding());
1541 }
1542
1543 static int
1544 rb_glob_caller(const char *path, VALUE a, void *enc)
1545 {
1546 int status;
1547 struct glob_args *args = (struct glob_args *)a;
1548
1549 args->path = path;
1550 rb_protect(glob_func_caller, a, &status);
1551 return status;
1552 }
1553
1554 static int
1555 rb_glob2(const char *path, int flags,
1556 void (*func)(const char *, VALUE, void *), VALUE arg,
1557 rb_encoding* enc)
1558 {
1559 struct glob_args args;
1560
1561 args.func = func;
1562 args.value = arg;
1563 args.enc = enc;
1564
1565 if (flags & FNM_SYSCASE) {
1566 rb_warning("Dir.glob() ignores File::FNM_CASEFOLD");
1567 }
1568
1569 return ruby_glob0(path, flags | GLOB_VERBOSE, rb_glob_caller, (VALUE)&args,
1570 enc);
1571 }
1572
1573 void
1574 rb_glob(const char *path, void (*func)(const char *, VALUE, void *), VALUE arg)
1575 {
1576 int status = rb_glob2(path, 0, func, arg, rb_ascii8bit_encoding());
1577 if (status) GLOB_JUMP_TAG(status);
1578 }
1579
1580 static void
1581 push_pattern(const char *path, VALUE ary, void *enc)
1582 {
1583 rb_ary_push(ary, rb_external_str_new_with_enc(path, strlen(path), enc));
1584 }
1585
1586 static int
1587 ruby_brace_expand(const char *str, int flags, ruby_glob_func *func, VALUE arg,
1588 rb_encoding *enc)
1589 {
1590 const int escape = !(flags & FNM_NOESCAPE);
1591 const char *p = str;
1592 const char *pend = p + strlen(p);
1593 const char *s = p;
1594 const char *lbrace = 0, *rbrace = 0;
1595 int nest = 0, status = 0;
1596
1597 while (*p) {
1598 if (*p == '{' && nest++ == 0) {
1599 lbrace = p;
1600 }
1601 if (*p == '}' && --nest <= 0) {
1602 rbrace = p;
1603 break;
1604 }
1605 if (*p == '\\' && escape) {
1606 if (!*++p) break;
1607 }
1608 Inc(p, pend, enc);
1609 }
1610
1611 if (lbrace && rbrace) {
1612 size_t len = strlen(s) + 1;
1613 char *buf = GLOB_ALLOC_N(char, len);
1614 long shift;
1615
1616 if (!buf) return -1;
1617 memcpy(buf, s, lbrace-s);
1618 shift = (lbrace-s);
1619 p = lbrace;
1620 while (p < rbrace) {
1621 const char *t = ++p;
1622 nest = 0;
1623 while (p < rbrace && !(*p == ',' && nest == 0)) {
1624 if (*p == '{') nest++;
1625 if (*p == '}') nest--;
1626 if (*p == '\\' && escape) {
1627 if (++p == rbrace) break;
1628 }
1629 Inc(p, pend, enc);
1630 }
1631 memcpy(buf+shift, t, p-t);
1632 strlcpy(buf+shift+(p-t), rbrace+1, len-(shift+(p-t)));
1633 status = ruby_brace_expand(buf, flags, func, arg, enc);
1634 if (status) break;
1635 }
1636 GLOB_FREE(buf);
1637 }
1638 else if (!lbrace && !rbrace) {
1639 status = (*func)(s, arg, enc);
1640 }
1641
1642 return status;
1643 }
1644
1645 struct brace_args {
1646 ruby_glob_func *func;
1647 VALUE value;
1648 int flags;
1649 };
1650
1651 static int
1652 glob_brace(const char *path, VALUE val, void *enc)
1653 {
1654 struct brace_args *arg = (struct brace_args *)val;
1655
1656 return ruby_glob0(path, arg->flags, arg->func, arg->value, enc);
1657 }
1658
1659 static int
1660 ruby_brace_glob0(const char *str, int flags, ruby_glob_func *func, VALUE arg,
1661 rb_encoding* enc)
1662 {
1663 struct brace_args args;
1664
1665 args.func = func;
1666 args.value = arg;
1667 args.flags = flags;
1668 return ruby_brace_expand(str, flags, glob_brace, (VALUE)&args, enc);
1669 }
1670
1671 int
1672 ruby_brace_glob(const char *str, int flags, ruby_glob_func *func, VALUE arg)
1673 {
1674 return ruby_brace_glob0(str, flags & ~GLOB_VERBOSE, func, arg,
1675 rb_ascii8bit_encoding());
1676 }
1677
1678 int
1679 ruby_brace_glob_with_enc(const char *str, int flags, ruby_glob_func *func, VALUE arg, rb_encoding *enc)
1680 {
1681 return ruby_brace_glob0(str, flags & ~GLOB_VERBOSE, func, arg, enc);
1682 }
1683
1684 static int
1685 push_glob(VALUE ary, VALUE str, int flags)
1686 {
1687 struct glob_args args;
1688 rb_encoding *enc = rb_enc_get(str);
1689
1690 if (enc == rb_usascii_encoding()) enc = rb_filesystem_encoding();
1691 args.func = push_pattern;
1692 args.value = ary;
1693 args.enc = enc;
1694
1695 RB_GC_GUARD(str);
1696 return ruby_brace_glob0(RSTRING_PTR(str), flags | GLOB_VERBOSE,
1697 rb_glob_caller, (VALUE)&args, enc);
1698 }
1699
1700 static VALUE
1701 rb_push_glob(VALUE str, int flags) /* '\0' is delimiter */
1702 {
1703 long offset = 0;
1704 VALUE ary;
1705
1706 GlobPathValue(str, TRUE);
1707 ary = rb_ary_new();
1708
1709 while (offset < RSTRING_LEN(str)) {
1710 char *p, *pend;
1711 int status;
1712 p = RSTRING_PTR(str) + offset;
1713 status = push_glob(ary, rb_enc_str_new(p, strlen(p), rb_enc_get(str)),
1714 flags);
1715 if (status) GLOB_JUMP_TAG(status);
1716 if (offset >= RSTRING_LEN(str)) break;
1717 p += strlen(p) + 1;
1718 pend = RSTRING_PTR(str) + RSTRING_LEN(str);
1719 while (p < pend && !*p)
1720 p++;
1721 offset = p - RSTRING_PTR(str);
1722 }
1723
1724 return ary;
1725 }
1726
1727 static VALUE
1728 dir_globs(long argc, VALUE *argv, int flags)
1729 {
1730 VALUE ary = rb_ary_new();
1731 long i;
1732
1733 for (i = 0; i < argc; ++i) {
1734 int status;
1735 VALUE str = argv[i];
1736 GlobPathValue(str, TRUE);
1737 status = push_glob(ary, str, flags);
1738 if (status) GLOB_JUMP_TAG(status);
1739 }
1740
1741 return ary;
1742 }
1743
1744 /*
1745 * call-seq:
1746 * Dir[ array ] -> array
1747 * Dir[ string [, string ...] ] -> array
1748 *
1749 * Equivalent to calling
1750 * <code>Dir.glob(</code><i>array,</i><code>0)</code> and
1751 * <code>Dir.glob([</code><i>string,...</i><code>],0)</code>.
1752 *
1753 */
1754 static VALUE
1755 dir_s_aref(int argc, VALUE *argv, VALUE obj)
1756 {
1757 if (argc == 1) {
1758 return rb_push_glob(argv[0], 0);
1759 }
1760 return dir_globs(argc, argv, 0);
1761 }
1762
1763 /*
1764 * call-seq:
1765 * Dir.glob( pattern, [flags] ) -> array
1766 * Dir.glob( pattern, [flags] ) {| filename | block } -> nil
1767 *
1768 * Returns the filenames found by expanding <i>pattern</i> which is
1769 * an +Array+ of the patterns or the pattern +String+, either as an
1770 * <i>array</i> or as parameters to the block. Note that this pattern
1771 * is not a regexp (it's closer to a shell glob). See
1772 * <code>File::fnmatch</code> for the meaning of the <i>flags</i>
1773 * parameter. Note that case sensitivity depends on your system (so
1774 * <code>File::FNM_CASEFOLD</code> is ignored), as does the order
1775 * in which the results are returned.
1776 *
1777 * <code>*</code>:: Matches any file. Can be restricted by
1778 * other values in the glob. <code>*</code>
1779 * will match all files; <code>c*</code> will
1780 * match all files beginning with
1781 * <code>c</code>; <code>*c</code> will match
1782 * all files ending with <code>c</code>; and
1783 * <code>\*c\*</code> will match all files that
1784 * have <code>c</code> in them (including at
1785 * the beginning or end). Equivalent to
1786 * <code>/ .* /x</code> in regexp. Note, this
1787 * will not match Unix-like hidden files (dotfiles).
1788 * In order to include those in the match results,
1789 * you must use something like <code>"{*,.*}"</code>.
1790 * <code>**</code>:: Matches directories recursively.
1791 * <code>?</code>:: Matches any one character. Equivalent to
1792 * <code>/.{1}/</code> in regexp.
1793 * <code>[set]</code>:: Matches any one character in +set+.
1794 * Behaves exactly like character sets in
1795 * Regexp, including set negation
1796 * (<code>[^a-z]</code>).
1797 * <code>{p,q}</code>:: Matches either literal <code>p</code> or
1798 * literal <code>q</code>. Matching literals
1799 * may be more than one character in length.
1800 * More than two literals may be specified.
1801 * Equivalent to pattern alternation in
1802 * regexp.
1803 * <code> \\ </code>:: Escapes the next metacharacter.
1804 * Note that this means you cannot use backslash
1805 * in windows as part of a glob,
1806 * i.e. <code>Dir["c:\\foo*"]</code> will not work,
1807 * use <code>Dir["c:/foo*"]</code> instead.
1808 *
1809 * Dir["config.?"] #=> ["config.h"]
1810 * Dir.glob("config.?") #=> ["config.h"]
1811 * Dir.glob("*.[a-z][a-z]") #=> ["main.rb"]
1812 * Dir.glob("*.[^r]*") #=> ["config.h"]
1813 * Dir.glob("*.{rb,h}") #=> ["main.rb", "config.h"]
1814 * Dir.glob("*") #=> ["config.h", "main.rb"]
1815 * Dir.glob("*", File::FNM_DOTMATCH) #=> [".", "..", "config.h", "main.rb"]
1816 *
1817 * rbfiles = File.join("**", "*.rb")
1818 * Dir.glob(rbfiles) #=> ["main.rb",
1819 * # "lib/song.rb",
1820 * # "lib/song/karaoke.rb"]
1821 * libdirs = File.join("**", "lib")
1822 * Dir.glob(libdirs) #=> ["lib"]
1823 *
1824 * librbfiles = File.join("**", "lib", "**", "*.rb")
1825 * Dir.glob(librbfiles) #=> ["lib/song.rb",
1826 * # "lib/song/karaoke.rb"]
1827 *
1828 * librbfiles = File.join("**", "lib", "*.rb")
1829 * Dir.glob(librbfiles) #=> ["lib/song.rb"]
1830 */
1831 static VALUE
1832 dir_s_glob(int argc, VALUE *argv, VALUE obj)
1833 {
1834 VALUE str, rflags, ary;
1835 int flags;
1836
1837 if (rb_scan_args(argc, argv, "11", &str, &rflags) == 2)
1838 flags = NUM2INT(rflags);
1839 else
1840 flags = 0;
1841
1842 ary = rb_check_array_type(str);
1843 if (NIL_P(ary)) {
1844 ary = rb_push_glob(str, flags);
1845 }
1846 else {
1847 volatile VALUE v = ary;
1848 ary = dir_globs(RARRAY_LEN(v), RARRAY_PTR(v), flags);
1849 }
1850
1851 if (rb_block_given_p()) {
1852 rb_ary_each(ary);
1853 return Qnil;
1854 }
1855 return ary;
1856 }
1857
1858 static VALUE
1859 dir_open_dir(int argc, VALUE *argv)
1860 {
1861 VALUE dir = rb_funcall2(rb_cDir, rb_intern("open"), argc, argv);
1862
1863 rb_check_typeddata(dir, &dir_data_type);
1864 return dir;
1865 }
1866
1867
1868 /*
1869 * call-seq:
1870 * Dir.foreach( dirname ) {| filename | block } -> nil
1871 * Dir.foreach( dirname ) -> an_enumerator
1872 *
1873 * Calls the block once for each entry in the named directory, passing
1874 * the filename of each entry as a parameter to the block.
1875 *
1876 * If no block is given, an enumerator is returned instead.
1877 *
1878 * Dir.foreach("testdir") {|x| puts "Got #{x}" }
1879 *
1880 * <em>produces:</em>
1881 *
1882 * Got .
1883 * Got ..
1884 * Got config.h
1885 * Got main.rb
1886 *
1887 */
1888 static VALUE
1889 dir_foreach(int argc, VALUE *argv, VALUE io)
1890 {
1891 VALUE dir;
1892
1893 RETURN_ENUMERATOR(io, argc, argv);
1894 dir = dir_open_dir(argc, argv);
1895 rb_ensure(dir_each, dir, dir_close, dir);
1896 return Qnil;
1897 }
1898
1899 /*
1900 * call-seq:
1901 * Dir.entries( dirname ) -> array
1902 *
1903 * Returns an array containing all of the filenames in the given
1904 * directory. Will raise a <code>SystemCallError</code> if the named
1905 * directory doesn't exist.
1906 *
1907 * Dir.entries("testdir") #=> [".", "..", "config.h", "main.rb"]
1908 *
1909 */
1910 static VALUE
1911 dir_entries(int argc, VALUE *argv, VALUE io)
1912 {
1913 VALUE dir;
1914
1915 dir = dir_open_dir(argc, argv);
1916 return rb_ensure(rb_Array, dir, dir_close, dir);
1917 }
1918
1919 static int
1920 fnmatch_brace(const char *pattern, VALUE val, void *enc)
1921 {
1922 struct brace_args *arg = (struct brace_args *)val;
1923 VALUE path = arg->value;
1924 rb_encoding *enc_pattern = enc;
1925 rb_encoding *enc_path = rb_enc_get(path);
1926
1927 if (enc_pattern != enc_path) {
1928 if (!rb_enc_asciicompat(enc_pattern))
1929 return FNM_NOMATCH;
1930 if (!rb_enc_asciicompat(enc_path))
1931 return FNM_NOMATCH;
1932 if (!rb_enc_str_asciionly_p(path)) {
1933 int cr = ENC_CODERANGE_7BIT;
1934 long len = strlen(pattern);
1935 if (rb_str_coderange_scan_restartable(pattern, pattern + len,
1936 enc_pattern, &cr) != len)
1937 return FNM_NOMATCH;
1938 if (cr != ENC_CODERANGE_7BIT)
1939 return FNM_NOMATCH;
1940 }
1941 }
1942 return (fnmatch(pattern, enc, RSTRING_PTR(path), arg->flags) == 0);
1943 }
1944
1945 /*
1946 * call-seq:
1947 * File.fnmatch( pattern, path, [flags] ) -> (true or false)
1948 * File.fnmatch?( pattern, path, [flags] ) -> (true or false)
1949 *
1950 * Returns true if <i>path</i> matches against <i>pattern</i> The
1951 * pattern is not a regular expression; instead it follows rules
1952 * similar to shell filename globbing. It may contain the following
1953 * metacharacters:
1954 *
1955 * <code>*</code>:: Matches any file. Can be restricted by
1956 * other values in the glob. <code>*</code>
1957 * will match all files; <code>c*</code> will
1958 * match all files beginning with
1959 * <code>c</code>; <code>*c</code> will match
1960 * all files ending with <code>c</code>; and
1961 * <code>\*c*</code> will match all files that
1962 * have <code>c</code> in them (including at
1963 * the beginning or end). Equivalent to
1964 * <code>/ .* /x</code> in regexp.
1965 * <code>**</code>:: Matches directories recursively or files
1966 * expansively.
1967 * <code>?</code>:: Matches any one character. Equivalent to
1968 * <code>/.{1}/</code> in regexp.
1969 * <code>[set]</code>:: Matches any one character in +set+.
1970 * Behaves exactly like character sets in
1971 * Regexp, including set negation
1972 * (<code>[^a-z]</code>).
1973 * <code> \ </code>:: Escapes the next metacharacter.
1974 *
1975 * <i>flags</i> is a bitwise OR of the <code>FNM_xxx</code>
1976 * parameters. The same glob pattern and flags are used by
1977 * <code>Dir::glob</code>.
1978 *
1979 * File.fnmatch('cat', 'cat') #=> true # match entire string
1980 * File.fnmatch('cat', 'category') #=> false # only match partial string
1981 * File.fnmatch('c{at,ub}s', 'cats') #=> false # { } isn't supported
1982 *
1983 * File.fnmatch('c?t', 'cat') #=> true # '?' match only 1 character
1984 * File.fnmatch('c??t', 'cat') #=> false # ditto
1985 * File.fnmatch('c*', 'cats') #=> true # '*' match 0 or more characters
1986 * File.fnmatch('c*t', 'c/a/b/t') #=> true # ditto
1987 * File.fnmatch('ca[a-z]', 'cat') #=> true # inclusive bracket expression
1988 * File.fnmatch('ca[^t]', 'cat') #=> false # exclusive bracket expression ('^' or '!')
1989 *
1990 * File.fnmatch('cat', 'CAT') #=> false # case sensitive
1991 * File.fnmatch('cat', 'CAT', File::FNM_CASEFOLD) #=> true # case insensitive
1992 *
1993 * File.fnmatch('?', '/', File::FNM_PATHNAME) #=> false # wildcard doesn't match '/' on FNM_PATHNAME
1994 * File.fnmatch('*', '/', File::FNM_PATHNAME) #=> false # ditto
1995 * File.fnmatch('[/]', '/', File::FNM_PATHNAME) #=> false # ditto
1996 *
1997 * File.fnmatch('\?', '?') #=> true # escaped wildcard becomes ordinary
1998 * File.fnmatch('\a', 'a') #=> true # escaped ordinary remains ordinary
1999 * File.fnmatch('\a', '\a', File::FNM_NOESCAPE) #=> true # FNM_NOESCAPE makes '\' ordinary
2000 * File.fnmatch('[\?]', '?') #=> true # can escape inside bracket expression
2001 *
2002 * File.fnmatch('*', '.profile') #=> false # wildcard doesn't match leading
2003 * File.fnmatch('*', '.profile', File::FNM_DOTMATCH) #=> true # period by default.
2004 * File.fnmatch('.*', '.profile') #=> true
2005 *
2006 * rbfiles = '**' '/' '*.rb' # you don't have to do like this. just write in single string.
2007 * File.fnmatch(rbfiles, 'main.rb') #=> false
2008 * File.fnmatch(rbfiles, './main.rb') #=> false
2009 * File.fnmatch(rbfiles, 'lib/song.rb') #=> true
2010 * File.fnmatch('**.rb', 'main.rb') #=> true
2011 * File.fnmatch('**.rb', './main.rb') #=> false
2012 * File.fnmatch('**.rb', 'lib/song.rb') #=> true
2013 * File.fnmatch('*', 'dave/.profile') #=> true
2014 *
2015 * pattern = '*' '/' '*'
2016 * File.fnmatch(pattern, 'dave/.profile', File::FNM_PATHNAME) #=> false
2017 * File.fnmatch(pattern, 'dave/.profile', File::FNM_PATHNAME | File::FNM_DOTMATCH) #=> true
2018 *
2019 * pattern = '**' '/' 'foo'
2020 * File.fnmatch(pattern, 'a/b/c/foo', File::FNM_PATHNAME) #=> true
2021 * File.fnmatch(pattern, '/a/b/c/foo', File::FNM_PATHNAME) #=> true
2022 * File.fnmatch(pattern, 'c:/a/b/c/foo', File::FNM_PATHNAME) #=> true
2023 * File.fnmatch(pattern, 'a/.b/c/foo', File::FNM_PATHNAME) #=> false
2024 * File.fnmatch(pattern, 'a/.b/c/foo', File::FNM_PATHNAME | File::FNM_DOTMATCH) #=> true
2025 */
2026 static VALUE
2027 file_s_fnmatch(int argc, VALUE *argv, VALUE obj)
2028 {
2029 VALUE pattern, path;
2030 VALUE rflags;
2031 int flags;
2032
2033 if (rb_scan_args(argc, argv, "21", &pattern, &path, &rflags) == 3)
2034 flags = NUM2INT(rflags);
2035 else
2036 flags = 0;
2037
2038 StringValue(pattern);
2039 FilePathStringValue(path);
2040
2041 if (flags & FNM_EXTGLOB) {
2042 struct brace_args args;
2043
2044 args.value = path;
2045 args.flags = flags;
2046 if (ruby_brace_expand(RSTRING_PTR(pattern), flags, fnmatch_brace,
2047 (VALUE)&args, rb_enc_get(pattern)) > 0)
2048 return Qtrue;
2049 }
2050 else {
2051 rb_encoding *enc = rb_enc_compatible(pattern, path);
2052 if (!enc) return Qfalse;
2053 if (fnmatch(RSTRING_PTR(pattern), enc, RSTRING_PTR(path), flags) == 0)
2054 return Qtrue;
2055 }
2056 RB_GC_GUARD(pattern);
2057
2058 return Qfalse;
2059 }
2060
2061 /*
2062 * call-seq:
2063 * Dir.home() -> "/home/me"
2064 * Dir.home("root") -> "/root"
2065 *
2066 * Returns the home directory of the current user or the named user
2067 * if given.
2068 */
2069 static VALUE
2070 dir_s_home(int argc, VALUE *argv, VALUE obj)
2071 {
2072 VALUE user;
2073 const char *u = 0;
2074
2075 rb_scan_args(argc, argv, "01", &user);
2076 if (!NIL_P(user)) {
2077 SafeStringValue(user);
2078 u = StringValueCStr(user);
2079 }
2080 return rb_home_dir(u, rb_str_new(0, 0));
2081 }
2082
2083 #if 0
2084 /*
2085 * call-seq:
2086 * Dir.exist?(file_name) -> true or false
2087 * Dir.exists?(file_name) -> true or false
2088 *
2089 * Returns <code>true</code> if the named file is a directory,
2090 * <code>false</code> otherwise.
2091 *
2092 */
2093 VALUE
2094 rb_file_directory_p()
2095 {
2096 }
2097 #endif
2098
2099 /*
2100 * Objects of class <code>Dir</code> are directory streams representing
2101 * directories in the underlying file system. They provide a variety of
2102 * ways to list directories and their contents. See also
2103 * <code>File</code>.
2104 *
2105 * The directory used in these examples contains the two regular files
2106 * (<code>config.h</code> and <code>main.rb</code>), the parent
2107 * directory (<code>..</code>), and the directory itself
2108 * (<code>.</code>).
2109 */
2110 void
2111 Init_Dir(void)
2112 {
2113 rb_cDir = rb_define_class("Dir", rb_cObject);
2114
2115 rb_include_module(rb_cDir, rb_mEnumerable);
2116
2117 rb_define_alloc_func(rb_cDir, dir_s_alloc);
2118 rb_define_singleton_method(rb_cDir, "open", dir_s_open, -1);
2119 rb_define_singleton_method(rb_cDir, "foreach", dir_foreach, -1);
2120 rb_define_singleton_method(rb_cDir, "entries", dir_entries, -1);
2121
2122 rb_define_method(rb_cDir,"initialize", dir_initialize, -1);
2123 rb_define_method(rb_cDir,"path", dir_path, 0);
2124 rb_define_method(rb_cDir,"to_path", dir_path, 0);
2125 rb_define_method(rb_cDir,"inspect", dir_inspect, 0);
2126 rb_define_method(rb_cDir,"read", dir_read, 0);
2127 rb_define_method(rb_cDir,"each", dir_each, 0);
2128 rb_define_method(rb_cDir,"rewind", dir_rewind, 0);
2129 rb_define_method(rb_cDir,"tell", dir_tell, 0);
2130 rb_define_method(rb_cDir,"seek", dir_seek, 1);
2131 rb_define_method(rb_cDir,"pos", dir_tell, 0);
2132 rb_define_method(rb_cDir,"pos=", dir_set_pos, 1);
2133 rb_define_method(rb_cDir,"close", dir_close, 0);
2134
2135 rb_define_singleton_method(rb_cDir,"chdir", dir_s_chdir, -1);
2136 rb_define_singleton_method(rb_cDir,"getwd", dir_s_getwd, 0);
2137 rb_define_singleton_method(rb_cDir,"pwd", dir_s_getwd, 0);
2138 rb_define_singleton_method(rb_cDir,"chroot", dir_s_chroot, 1);
2139 rb_define_singleton_method(rb_cDir,"mkdir", dir_s_mkdir, -1);
2140 rb_define_singleton_method(rb_cDir,"rmdir", dir_s_rmdir, 1);
2141 rb_define_singleton_method(rb_cDir,"delete", dir_s_rmdir, 1);
2142 rb_define_singleton_method(rb_cDir,"unlink", dir_s_rmdir, 1);
2143 rb_define_singleton_method(rb_cDir,"home", dir_s_home, -1);
2144
2145 rb_define_singleton_method(rb_cDir,"glob", dir_s_glob, -1);
2146 rb_define_singleton_method(rb_cDir,"[]", dir_s_aref, -1);
2147 rb_define_singleton_method(rb_cDir,"exist?", rb_file_directory_p, 1);
2148 rb_define_singleton_method(rb_cDir,"exists?", rb_file_directory_p, 1);
2149
2150 rb_define_singleton_method(rb_cFile,"fnmatch", file_s_fnmatch, -1);
2151 rb_define_singleton_method(rb_cFile,"fnmatch?", file_s_fnmatch, -1);
2152
2153 rb_file_const("FNM_NOESCAPE", INT2FIX(FNM_NOESCAPE));
2154 rb_file_const("FNM_PATHNAME", INT2FIX(FNM_PATHNAME));
2155 rb_file_const("FNM_DOTMATCH", INT2FIX(FNM_DOTMATCH));
2156 rb_file_const("FNM_CASEFOLD", INT2FIX(FNM_CASEFOLD));
2157 rb_file_const("FNM_EXTGLOB", INT2FIX(FNM_EXTGLOB));
2158 rb_file_const("FNM_SYSCASE", INT2FIX(FNM_SYSCASE));
2159 }
2160