dir.c
DEFINITIONS
This source file includes following functions.
- NAMLEN
- NAMLEN
- NAMLEN
- CharNext
- CharNext
- find_dirsep
- range
- fnmatch
- free_dir
- dir_s_alloc
- dir_initialize
- dir_s_open
- dir_closed
- dir_path
- dir_read
- dir_each
- dir_tell
- dir_seek
- dir_set_pos
- dir_rewind
- dir_close
- dir_chdir
- chdir_restore
- dir_s_chdir
- dir_s_getwd
- dir_s_chroot
- dir_s_mkdir
- dir_s_rmdir
- has_magic
- extract_path
- extract_elem
- remove_backslashes
- S_ISDIR
- glob_helper
- rb_glob2
- rb_glob
- rb_globi
- push_pattern
- push_globs
- push_braces
- rb_push_glob
- dir_s_aref
- dir_s_glob
- dir_foreach
- dir_entries
- file_s_fnmatch
- Init_Dir
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 #include "ruby.h"
16
17 #include <sys/types.h>
18 #include <sys/stat.h>
19
20 #ifdef HAVE_SYS_PARAM_H
21 # include <sys/param.h>
22 #else
23 # define MAXPATHLEN 1024
24 #endif
25 #ifdef HAVE_UNISTD_H
26 #include <unistd.h>
27 #endif
28
29 #if defined HAVE_DIRENT_H && !defined NT
30 # include <dirent.h>
31 # define NAMLEN(dirent) strlen((dirent)->d_name)
32 #elif defined HAVE_DIRECT_H && !defined NT
33 # include <direct.h>
34 # define NAMLEN(dirent) strlen((dirent)->d_name)
35 #else
36 # define dirent direct
37 # define NAMLEN(dirent) (dirent)->d_namlen
38 # if HAVE_SYS_NDIR_H
39 # include <sys/ndir.h>
40 # endif
41 # if HAVE_SYS_DIR_H
42 # include <sys/dir.h>
43 # endif
44 # if HAVE_NDIR_H
45 # include <ndir.h>
46 # endif
47 # if defined(NT)
48 # include "win32/dir.h"
49 # endif
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 "util.h"
65
66 #ifndef HAVE_LSTAT
67 #define lstat(path,st) stat(path,st)
68 #endif
69
70 #define FNM_NOESCAPE 0x01
71 #define FNM_PATHNAME 0x02
72 #define FNM_DOTMATCH 0x04
73 #define FNM_CASEFOLD 0x08
74
75 #define FNM_NOMATCH 1
76 #define FNM_ERROR 2
77
78 #define downcase(c) (nocase && ISUPPER(c) ? tolower(c) : (c))
79
80 #ifndef CharNext
81 # if defined(DJGPP)
82 # define CharNext(p) ((p) + mblen(p, MB_CUR_MAX))
83 # else
84 # define CharNext(p) ((p) + 1)
85 # endif
86 #endif
87 #if defined DOSISH
88 #define isdirsep(c) ((c) == '/' || (c) == '\\')
89 static char *
90 find_dirsep(s)
91 char *s;
92 {
93 while (*s) {
94 if (isdirsep(*s))
95 return s;
96 s = CharNext(s);
97 }
98 return 0;
99 }
100 #else
101 #define isdirsep(c) ((c) == '/')
102 #define find_dirsep(s) strchr(s, '/')
103 #endif
104
105 static char *
106 range(pat, test, flags)
107 char *pat;
108 char test;
109 int flags;
110 {
111 int not, ok = 0;
112 int nocase = flags & FNM_CASEFOLD;
113 int escape = !(flags & FNM_NOESCAPE);
114
115 not = *pat == '!' || *pat == '^';
116 if (not)
117 pat++;
118
119 test = downcase(test);
120
121 while (*pat) {
122 int cstart, cend;
123 cstart = cend = *pat++;
124 if (cstart == ']')
125 return ok == not ? 0 : pat;
126 else if (escape && cstart == '\\')
127 cstart = cend = *pat++;
128 if (*pat == '-' && pat[1] != ']') {
129 if (escape && pat[1] == '\\')
130 pat++;
131 cend = pat[1];
132 if (!cend)
133 return 0;
134 pat += 2;
135 }
136 if (downcase(cstart) <= test && test <= downcase(cend))
137 ok = 1;
138 }
139 return 0;
140 }
141
142 #define ISDIRSEP(c) (pathname && isdirsep(c))
143 #define PERIOD(s) (period && *(s) == '.' && \
144 ((s) == string || ISDIRSEP((s)[-1])))
145 static int
146 fnmatch(pat, string, flags)
147 const char *pat;
148 const char *string;
149 int flags;
150 {
151 int c;
152 int test;
153 const char *s = string;
154 int escape = !(flags & FNM_NOESCAPE);
155 int pathname = flags & FNM_PATHNAME;
156 int period = !(flags & FNM_DOTMATCH);
157 int nocase = flags & FNM_CASEFOLD;
158
159 while (c = *pat++) {
160 switch (c) {
161 case '?':
162 if (!*s || ISDIRSEP(*s) || PERIOD(s))
163 return FNM_NOMATCH;
164 s++;
165 break;
166 case '*':
167 while ((c = *pat++) == '*')
168 ;
169
170 if (PERIOD(s))
171 return FNM_NOMATCH;
172
173 if (!c) {
174 if (pathname && find_dirsep(s))
175 return FNM_NOMATCH;
176 else
177 return 0;
178 }
179 else if (ISDIRSEP(c)) {
180 s = find_dirsep(s);
181 if (s) {
182 s++;
183 break;
184 }
185 return FNM_NOMATCH;
186 }
187
188 test = escape && c == '\\' ? *pat : c;
189 test = downcase(test);
190 pat--;
191 while (*s) {
192 if ((c == '[' || downcase(*s) == test) &&
193 !fnmatch(pat, s, flags | FNM_DOTMATCH))
194 return 0;
195 else if (ISDIRSEP(*s))
196 break;
197 s++;
198 }
199 return FNM_NOMATCH;
200
201 case '[':
202 if (!*s || ISDIRSEP(*s) || PERIOD(s))
203 return FNM_NOMATCH;
204 pat = range(pat, *s, flags);
205 if (!pat)
206 return FNM_NOMATCH;
207 s++;
208 break;
209
210 case '\\':
211 if (escape
212 #if defined DOSISH
213 && *pat && strchr("*?[\\", *pat)
214 #endif
215 ) {
216 c = *pat;
217 if (!c)
218 c = '\\';
219 else
220 pat++;
221 }
222
223
224 default:
225 #if defined DOSISH
226 if (ISDIRSEP(c) && isdirsep(*s))
227 ;
228 else
229 #endif
230 if(downcase(c) != downcase(*s))
231 return FNM_NOMATCH;
232 s++;
233 break;
234 }
235 }
236 return !*s ? 0 : FNM_NOMATCH;
237 }
238
239 VALUE rb_cDir;
240
241 struct dir_data {
242 DIR *dir;
243 char *path;
244 };
245
246 static void
247 free_dir(dir)
248 struct dir_data *dir;
249 {
250 if (dir && dir->dir) closedir(dir->dir);
251 }
252
253 static VALUE dir_close _((VALUE));
254
255 static VALUE
256 dir_s_alloc(klass)
257 VALUE klass;
258 {
259 struct dir_data *dirp;
260 VALUE obj = Data_Make_Struct(klass, struct dir_data, 0, free_dir, dirp);
261
262 dirp->dir = NULL;
263 dirp->path = NULL;
264
265 return obj;
266 }
267
268 static VALUE
269 dir_initialize(dir, dirname)
270 VALUE dir, dirname;
271 {
272 struct dir_data *dp;
273
274 SafeStringValue(dirname);
275 Data_Get_Struct(dir, struct dir_data, dp);
276 if (dp->dir) closedir(dp->dir);
277 if (dp->path) free(dp->path);
278 dp->dir = NULL;
279 dp->path = NULL;
280 dp->dir = opendir(RSTRING(dirname)->ptr);
281 if (dp->dir == NULL) {
282 if (errno == EMFILE || errno == ENFILE) {
283 rb_gc();
284 dp->dir = opendir(RSTRING(dirname)->ptr);
285 }
286 if (dp->dir == NULL) {
287 rb_sys_fail(RSTRING(dirname)->ptr);
288 }
289 }
290 dp->path = strdup(RSTRING(dirname)->ptr);
291
292 return dir;
293 }
294
295 static VALUE
296 dir_s_open(klass, dirname)
297 VALUE klass, dirname;
298 {
299 struct dir_data *dp;
300 VALUE dir = Data_Make_Struct(klass, struct dir_data, 0, free_dir, dp);
301
302 dir_initialize(dir, dirname);
303 if (rb_block_given_p()) {
304 return rb_ensure(rb_yield, dir, dir_close, dir);
305 }
306
307 return dir;
308 }
309
310 static void
311 dir_closed()
312 {
313 rb_raise(rb_eIOError, "closed directory");
314 }
315
316 #define GetDIR(obj, dirp) do {\
317 Data_Get_Struct(obj, struct dir_data, dirp);\
318 if (dirp->dir == NULL) dir_closed();\
319 } while (0)
320
321 static VALUE
322 dir_path(dir)
323 VALUE dir;
324 {
325 struct dir_data *dirp;
326
327 GetDIR(dir, dirp);
328 if (!dirp->path) return Qnil;
329 return rb_str_new2(dirp->path);
330 }
331
332 static VALUE
333 dir_read(dir)
334 VALUE dir;
335 {
336 struct dir_data *dirp;
337 struct dirent *dp;
338
339 GetDIR(dir, dirp);
340 errno = 0;
341 dp = readdir(dirp->dir);
342 if (dp) {
343 return rb_tainted_str_new(dp->d_name, NAMLEN(dp));
344 }
345 else if (errno == 0) {
346 return Qnil;
347 }
348 else {
349 rb_sys_fail(0);
350 }
351 return Qnil;
352 }
353
354 static VALUE
355 dir_each(dir)
356 VALUE dir;
357 {
358 struct dir_data *dirp;
359 struct dirent *dp;
360
361 GetDIR(dir, dirp);
362 for (dp = readdir(dirp->dir); dp != NULL; dp = readdir(dirp->dir)) {
363 rb_yield(rb_tainted_str_new(dp->d_name, NAMLEN(dp)));
364 if (dirp->dir == NULL) dir_closed();
365 }
366 return dir;
367 }
368
369 static VALUE
370 dir_tell(dir)
371 VALUE dir;
372 {
373 #ifdef HAVE_TELLDIR
374 struct dir_data *dirp;
375 long pos;
376
377 GetDIR(dir, dirp);
378 pos = telldir(dirp->dir);
379 return rb_int2inum(pos);
380 #else
381 rb_notimplement();
382 #endif
383 }
384
385 static VALUE
386 dir_seek(dir, pos)
387 VALUE dir, pos;
388 {
389 struct dir_data *dirp;
390
391 #ifdef HAVE_SEEKDIR
392 GetDIR(dir, dirp);
393 seekdir(dirp->dir, NUM2INT(pos));
394 return dir;
395 #else
396 rb_notimplement();
397 #endif
398 }
399
400 static VALUE
401 dir_set_pos(dir, pos)
402 VALUE dir, pos;
403 {
404 dir_seek(dir, pos);
405 return pos;
406 }
407
408 static VALUE
409 dir_rewind(dir)
410 VALUE dir;
411 {
412 struct dir_data *dirp;
413
414 GetDIR(dir, dirp);
415 rewinddir(dirp->dir);
416 return dir;
417 }
418
419 static VALUE
420 dir_close(dir)
421 VALUE dir;
422 {
423 struct dir_data *dirp;
424
425 GetDIR(dir, dirp);
426 closedir(dirp->dir);
427 dirp->dir = NULL;
428
429 return Qnil;
430 }
431
432 static void
433 dir_chdir(path)
434 const char *path;
435 {
436 if (chdir(path) < 0)
437 rb_sys_fail(path);
438 }
439
440 static int chdir_blocking = 0;
441 static VALUE chdir_thread = Qnil;
442
443 static VALUE
444 chdir_restore(path)
445 char *path;
446 {
447 chdir_blocking--;
448 if (chdir_blocking == 0)
449 chdir_thread = Qnil;
450 dir_chdir(path);
451 free(path);
452 return Qnil;
453 }
454
455 static VALUE
456 dir_s_chdir(argc, argv, obj)
457 int argc;
458 VALUE *argv;
459 VALUE obj;
460 {
461 VALUE path = Qnil;
462 char *dist = "";
463
464 rb_secure(2);
465 if (rb_scan_args(argc, argv, "01", &path) == 1) {
466 SafeStringValue(path);
467 dist = RSTRING(path)->ptr;
468 }
469 else {
470 dist = getenv("HOME");
471 if (!dist) {
472 dist = getenv("LOGDIR");
473 if (!dist) rb_raise(rb_eArgError, "HOME/LOGDIR not set");
474 }
475 }
476
477 if (chdir_blocking > 0) {
478 if (!rb_block_given_p() || rb_thread_current() != chdir_thread)
479 rb_warn("conflicting chdir during another chdir block");
480 }
481
482 if (rb_block_given_p()) {
483 char *cwd = my_getcwd();
484 chdir_blocking++;
485 if (chdir_thread == Qnil)
486 chdir_thread = rb_thread_current();
487 dir_chdir(dist);
488 return rb_ensure(rb_yield, path, chdir_restore, (VALUE)cwd);
489 }
490 dir_chdir(dist);
491
492 return INT2FIX(0);
493 }
494
495 static VALUE
496 dir_s_getwd(dir)
497 VALUE dir;
498 {
499 char *path = my_getcwd();
500 VALUE cwd = rb_tainted_str_new2(path);
501
502 free(path);
503 return cwd;
504 }
505
506 static VALUE
507 dir_s_chroot(dir, path)
508 VALUE dir, path;
509 {
510 #if defined(HAVE_CHROOT) && !defined(__CHECKER__)
511 rb_secure(2);
512 SafeStringValue(path);
513
514 if (chroot(RSTRING(path)->ptr) == -1)
515 rb_sys_fail(RSTRING(path)->ptr);
516
517 return INT2FIX(0);
518 #else
519 rb_notimplement();
520 return Qnil;
521 #endif
522 }
523
524 static VALUE
525 dir_s_mkdir(argc, argv, obj)
526 int argc;
527 VALUE *argv;
528 VALUE obj;
529 {
530 VALUE path, vmode;
531 int mode;
532
533 if (rb_scan_args(argc, argv, "11", &path, &vmode) == 2) {
534 mode = NUM2INT(vmode);
535 }
536 else {
537 mode = 0777;
538 }
539
540 SafeStringValue(path);
541 rb_secure(2);
542 #if !defined(NT)
543 if (mkdir(RSTRING(path)->ptr, mode) == -1)
544 rb_sys_fail(RSTRING(path)->ptr);
545 #else
546 if (mkdir(RSTRING(path)->ptr) == -1)
547 rb_sys_fail(RSTRING(path)->ptr);
548 #endif
549
550 return INT2FIX(0);
551 }
552
553 static VALUE
554 dir_s_rmdir(obj, dir)
555 VALUE obj, dir;
556 {
557 SafeStringValue(dir);
558 rb_secure(2);
559 if (rmdir(RSTRING(dir)->ptr) < 0)
560 rb_sys_fail(RSTRING(dir)->ptr);
561
562 return INT2FIX(0);
563 }
564
565
566 static int
567 has_magic(s, send, flags)
568 char *s, *send;
569 int flags;
570 {
571 register char *p = s;
572 register char c;
573 int open = 0;
574 int escape = !(flags & FNM_NOESCAPE);
575
576 while ((c = *p++) != '\0') {
577 switch (c) {
578 case '?':
579 case '*':
580 return Qtrue;
581
582 case '[':
583 open++;
584 continue;
585 case ']':
586 if (open)
587 return Qtrue;
588 continue;
589
590 case '\\':
591 if (escape && *p++ == '\0')
592 return Qfalse;
593 }
594
595 if (send && p >= send) break;
596 }
597 return Qfalse;
598 }
599
600 static char*
601 extract_path(p, pend)
602 char *p, *pend;
603 {
604 char *alloc;
605 int len;
606
607 len = pend - p;
608 alloc = ALLOC_N(char, len+1);
609 memcpy(alloc, p, len);
610 if (len > 1 && pend[-1] == '/'
611 #if defined DOSISH
612 && pend[-2] != ':'
613 #endif
614 ) {
615 alloc[len-1] = 0;
616 }
617 else {
618 alloc[len] = 0;
619 }
620
621 return alloc;
622 }
623
624 static char*
625 extract_elem(path)
626 char *path;
627 {
628 char *pend;
629
630 pend = strchr(path, '/');
631 if (!pend) pend = path + strlen(path);
632
633 return extract_path(path, pend);
634 }
635
636 static void
637 remove_backslashes(p)
638 char *p;
639 {
640 char *pend = p + strlen(p);
641 char *t = p;
642
643 while (p < pend) {
644 if (*p == '\\') {
645 if (++p == pend) break;
646 }
647 *t++ = *p++;
648 }
649 *t = '\0';
650 }
651
652 #ifndef S_ISDIR
653 # define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR)
654 #endif
655
656 static void
657 glob_helper(path, sub, flags, func, arg)
658 char *path;
659 char *sub;
660 int flags;
661 void (*func) _((const char*, VALUE));
662 VALUE arg;
663 {
664 struct stat st;
665 char *p, *m;
666
667 p = sub ? sub : path;
668 if (!has_magic(p, 0, flags)) {
669 #if defined DOSISH
670 remove_backslashes(path);
671 #else
672 if (!(flags & FNM_NOESCAPE)) remove_backslashes(p);
673 #endif
674 if (lstat(path, &st) == 0) {
675 (*func)(path, arg);
676 }
677 else if (errno != ENOENT) {
678
679
680 rb_sys_warning(path);
681 }
682 return;
683 }
684
685 while (p) {
686 if (*p == '/') p++;
687 m = strchr(p, '/');
688 if (has_magic(p, m, flags)) {
689 char *dir, *base, *magic, *buf;
690 DIR *dirp;
691 struct dirent *dp;
692 int recursive = 0;
693
694 struct d_link {
695 char *path;
696 struct d_link *next;
697 } *tmp, *link = 0;
698
699 base = extract_path(path, p);
700 if (path == p) dir = ".";
701 else dir = base;
702
703 magic = extract_elem(p);
704 if (stat(dir, &st) < 0) {
705 if (errno != ENOENT) rb_sys_warning(dir);
706 free(base);
707 break;
708 }
709 if (S_ISDIR(st.st_mode)) {
710 if (m && strcmp(magic, "**") == 0) {
711 int n = strlen(base);
712 recursive = 1;
713 buf = ALLOC_N(char, n+strlen(m)+3);
714 sprintf(buf, "%s%s", base, *base ? m : m+1);
715 glob_helper(buf, buf+n, flags, func, arg);
716 free(buf);
717 }
718 dirp = opendir(dir);
719 if (dirp == NULL) {
720 rb_sys_warning(dir);
721 free(base);
722 break;
723 }
724 }
725 else {
726 free(base);
727 break;
728 }
729
730 #if defined DOSISH
731 #define BASE (*base && !((isdirsep(*base) && !base[1]) || (base[1] == ':' && isdirsep(base[2]) && !base[3])))
732 #else
733 #define BASE (*base && !(*base == '/' && !base[1]))
734 #endif
735
736 for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
737 if (recursive) {
738 if (strcmp(".", dp->d_name) == 0 || strcmp("..", dp->d_name) == 0)
739 continue;
740 buf = ALLOC_N(char, strlen(base)+NAMLEN(dp)+strlen(m)+6);
741 sprintf(buf, "%s%s%s", base, (BASE) ? "/" : "", dp->d_name);
742 if (lstat(buf, &st) < 0) {
743 if (errno != ENOENT) rb_sys_warning(buf);
744 continue;
745 }
746 if (S_ISDIR(st.st_mode)) {
747 char *t = buf+strlen(buf);
748 strcpy(t, "/**");
749 strcpy(t+3, m);
750 glob_helper(buf, t, flags, func, arg);
751 }
752 free(buf);
753 continue;
754 }
755 if (fnmatch(magic, dp->d_name, flags) == 0) {
756 buf = ALLOC_N(char, strlen(base)+NAMLEN(dp)+2);
757 sprintf(buf, "%s%s%s", base, (BASE) ? "/" : "", dp->d_name);
758 if (!m) {
759 (*func)(buf, arg);
760 free(buf);
761 continue;
762 }
763 tmp = ALLOC(struct d_link);
764 tmp->path = buf;
765 tmp->next = link;
766 link = tmp;
767 }
768 }
769 closedir(dirp);
770 free(base);
771 free(magic);
772 if (link) {
773 while (link) {
774 if (stat(link->path, &st) == 0) {
775 if (S_ISDIR(st.st_mode)) {
776 int len = strlen(link->path);
777 int mlen = strlen(m);
778 char *t = ALLOC_N(char, len+mlen+1);
779
780 sprintf(t, "%s%s", link->path, m);
781 glob_helper(t, t+len, flags, func, arg);
782 free(t);
783 }
784 }
785 else {
786 rb_sys_warning(link->path);
787 }
788 tmp = link;
789 link = link->next;
790 free(tmp->path);
791 free(tmp);
792 }
793 break;
794 }
795 }
796 p = m;
797 }
798 }
799
800 static void
801 rb_glob2(path, flags, func, arg)
802 char *path;
803 int flags;
804 void (*func) _((const char*, VALUE));
805 VALUE arg;
806 {
807 glob_helper(path, 0, flags, func, arg);
808 }
809
810 void
811 rb_glob(path, func, arg)
812 char *path;
813 void (*func) _((const char*, VALUE));
814 VALUE arg;
815 {
816 rb_glob2(path, 0, func, arg);
817 }
818
819 void
820 rb_globi(path, func, arg)
821 char *path;
822 void (*func) _((const char*, VALUE));
823 VALUE arg;
824 {
825 rb_glob2(path, FNM_CASEFOLD, func, arg);
826 }
827
828 static void
829 push_pattern(path, ary)
830 const char *path;
831 VALUE ary;
832 {
833 VALUE str = rb_tainted_str_new2(path);
834
835 if (ary) {
836 rb_ary_push(ary, str);
837 }
838 else {
839 rb_yield(str);
840 }
841 }
842
843 static void
844 push_globs(ary, s, flags)
845 VALUE ary;
846 char *s;
847 int flags;
848 {
849 rb_glob2(s, flags, push_pattern, ary);
850 }
851
852 static void
853 push_braces(ary, s, flags)
854 VALUE ary;
855 char *s;
856 int flags;
857 {
858 char *buf;
859 char *p, *t, *b;
860 char *lbrace, *rbrace;
861 int nest = 0;
862
863 p = s;
864 lbrace = rbrace = 0;
865 while (*p) {
866 if (*p == '{') {
867 lbrace = p;
868 break;
869 }
870 p++;
871 }
872 while (*p) {
873 if (*p == '{') nest++;
874 if (*p == '}' && --nest == 0) {
875 rbrace = p;
876 break;
877 }
878 p++;
879 }
880
881 if (lbrace) {
882 int len = strlen(s);
883 buf = xmalloc(len + 1);
884 memcpy(buf, s, lbrace-s);
885 b = buf + (lbrace-s);
886 p = lbrace;
887 while (*p != '}') {
888 t = p + 1;
889 for (p = t; *p!='}' && *p!=','; p++) {
890
891 if (*p == '{') while (*p!='}') p++;
892 }
893 memcpy(b, t, p-t);
894 strcpy(b+(p-t), rbrace+1);
895 push_braces(ary, buf, flags);
896 }
897 free(buf);
898 }
899 else {
900 push_globs(ary, s, flags);
901 }
902 }
903
904 #define isdelim(c) ((c)=='\0')
905
906 static VALUE
907 rb_push_glob(str, flags)
908 VALUE str;
909 int flags;
910 {
911 char *p, *pend;
912 char *buf;
913 char *t;
914 int nest, maxnest;
915 int noescape = flags & FNM_NOESCAPE;
916 VALUE ary;
917
918 if (rb_block_given_p())
919 ary = 0;
920 else
921 ary = rb_ary_new();
922
923 SafeStringValue(str);
924 buf = xmalloc(RSTRING(str)->len + 1);
925
926 p = RSTRING(str)->ptr;
927 pend = p + RSTRING(str)->len;
928
929 while (p < pend) {
930 t = buf;
931 nest = maxnest = 0;
932 while (p < pend && isdelim(*p)) p++;
933 while (p < pend && !isdelim(*p)) {
934 if (*p == '{') nest++, maxnest++;
935 if (*p == '}') nest--;
936 if (!noescape && *p == '\\') {
937 *t++ = *p++;
938 if (p == pend) break;
939 }
940 *t++ = *p++;
941 }
942 *t = '\0';
943 if (maxnest == 0) {
944 push_globs(ary, buf, flags);
945 }
946 else if (nest == 0) {
947 push_braces(ary, buf, flags);
948 }
949
950 }
951 free(buf);
952
953 return ary;
954 }
955
956 static VALUE
957 dir_s_aref(obj, str)
958 VALUE obj, str;
959 {
960 return rb_push_glob(str, 0);
961 }
962
963 static VALUE
964 dir_s_glob(argc, argv, obj)
965 int argc;
966 VALUE *argv;
967 VALUE obj;
968 {
969 VALUE str, rflags;
970 int flags;
971
972 if (rb_scan_args(argc, argv, "11", &str, &rflags) == 2)
973 flags = NUM2INT(rflags);
974 else
975 flags = 0;
976
977 return rb_push_glob(str, flags);
978 }
979
980 static VALUE
981 dir_foreach(io, dirname)
982 VALUE io, dirname;
983 {
984 VALUE dir;
985
986 dir = rb_funcall(rb_cDir, rb_intern("open"), 1, dirname);
987 rb_ensure(dir_each, dir, dir_close, dir);
988 return Qnil;
989 }
990
991 static VALUE
992 dir_entries(io, dirname)
993 VALUE io, dirname;
994 {
995 VALUE dir;
996
997 dir = rb_funcall(rb_cDir, rb_intern("open"), 1, dirname);
998 return rb_ensure(rb_Array, dir, dir_close, dir);
999 }
1000
1001 static VALUE
1002 file_s_fnmatch(argc, argv, obj)
1003 int argc;
1004 VALUE *argv;
1005 VALUE obj;
1006 {
1007 VALUE pattern, path;
1008 VALUE rflags;
1009 int flags;
1010
1011 if (rb_scan_args(argc, argv, "21", &pattern, &path, &rflags) == 3)
1012 flags = NUM2INT(rflags);
1013 else
1014 flags = 0;
1015
1016 StringValue(pattern);
1017 StringValue(path);
1018
1019 if (fnmatch(RSTRING(pattern)->ptr, RSTRING(path)->ptr, flags) == 0)
1020 return Qtrue;
1021
1022 return Qfalse;
1023 }
1024
1025 void
1026 Init_Dir()
1027 {
1028 rb_cDir = rb_define_class("Dir", rb_cObject);
1029
1030 rb_include_module(rb_cDir, rb_mEnumerable);
1031
1032 rb_define_singleton_method(rb_cDir, "allocate", dir_s_alloc, 0);
1033 rb_define_singleton_method(rb_cDir, "open", dir_s_open, 1);
1034 rb_define_singleton_method(rb_cDir, "foreach", dir_foreach, 1);
1035 rb_define_singleton_method(rb_cDir, "entries", dir_entries, 1);
1036
1037 rb_define_method(rb_cDir,"initialize", dir_initialize, 1);
1038 rb_define_method(rb_cDir,"path", dir_path, 0);
1039 rb_define_method(rb_cDir,"read", dir_read, 0);
1040 rb_define_method(rb_cDir,"each", dir_each, 0);
1041 rb_define_method(rb_cDir,"rewind", dir_rewind, 0);
1042 rb_define_method(rb_cDir,"tell", dir_tell, 0);
1043 rb_define_method(rb_cDir,"seek", dir_seek, 1);
1044 rb_define_method(rb_cDir,"pos", dir_tell, 0);
1045 rb_define_method(rb_cDir,"pos=", dir_set_pos, 1);
1046 rb_define_method(rb_cDir,"close", dir_close, 0);
1047
1048 rb_define_singleton_method(rb_cDir,"chdir", dir_s_chdir, -1);
1049 rb_define_singleton_method(rb_cDir,"getwd", dir_s_getwd, 0);
1050 rb_define_singleton_method(rb_cDir,"pwd", dir_s_getwd, 0);
1051 rb_define_singleton_method(rb_cDir,"chroot", dir_s_chroot, 1);
1052 rb_define_singleton_method(rb_cDir,"mkdir", dir_s_mkdir, -1);
1053 rb_define_singleton_method(rb_cDir,"rmdir", dir_s_rmdir, 1);
1054 rb_define_singleton_method(rb_cDir,"delete", dir_s_rmdir, 1);
1055 rb_define_singleton_method(rb_cDir,"unlink", dir_s_rmdir, 1);
1056
1057 rb_define_singleton_method(rb_cDir,"glob", dir_s_glob, -1);
1058 rb_define_singleton_method(rb_cDir,"[]", dir_s_aref, 1);
1059
1060 rb_define_singleton_method(rb_cFile,"fnmatch", file_s_fnmatch, -1);
1061 rb_define_singleton_method(rb_cFile,"fnmatch?", file_s_fnmatch, -1);
1062
1063 rb_file_const("FNM_NOESCAPE", INT2FIX(FNM_NOESCAPE));
1064 rb_file_const("FNM_PATHNAME", INT2FIX(FNM_PATHNAME));
1065 rb_file_const("FNM_DOTMATCH", INT2FIX(FNM_DOTMATCH));
1066 rb_file_const("FNM_CASEFOLD", INT2FIX(FNM_CASEFOLD));
1067 }