1 #include "ruby.h"
2 #include "ruby/encoding.h"
3 
4 static VALUE rb_cPathname;
5 static ID id_ENOTDIR;
6 static ID id_at_path;
7 static ID id_atime;
8 static ID id_base;
9 static ID id_basename;
10 static ID id_binread;
11 static ID id_binwrite;
12 static ID id_birthtime;
13 static ID id_blockdev_p;
14 static ID id_chardev_p;
15 static ID id_chmod;
16 static ID id_chown;
17 static ID id_ctime;
18 static ID id_directory_p;
19 static ID id_dirname;
20 static ID id_empty_p;
21 static ID id_entries;
22 static ID id_executable_p;
23 static ID id_executable_real_p;
24 static ID id_exist_p;
25 static ID id_expand_path;
26 static ID id_extname;
27 static ID id_file_p;
28 static ID id_fnmatch;
29 static ID id_foreach;
30 static ID id_ftype;
31 static ID id_getwd;
32 static ID id_glob;
33 static ID id_grpowned_p;
34 static ID id_lchmod;
35 static ID id_lchown;
36 static ID id_link;
37 static ID id_lstat;
38 static ID id_mkdir;
39 static ID id_mtime;
40 static ID id_open;
41 static ID id_owned_p;
42 static ID id_pipe_p;
43 static ID id_read;
44 static ID id_readable_p;
45 static ID id_readable_real_p;
46 static ID id_readlines;
47 static ID id_readlink;
48 static ID id_realdirpath;
49 static ID id_realpath;
50 static ID id_rename;
51 static ID id_rmdir;
52 static ID id_setgid_p;
53 static ID id_setuid_p;
54 static ID id_size;
55 static ID id_size_p;
56 static ID id_socket_p;
57 static ID id_split;
58 static ID id_stat;
59 static ID id_sticky_p;
60 static ID id_sub;
61 static ID id_symlink;
62 static ID id_symlink_p;
63 static ID id_sysopen;
64 static ID id_to_path;
65 static ID id_truncate;
66 static ID id_unlink;
67 static ID id_utime;
68 static ID id_world_readable_p;
69 static ID id_world_writable_p;
70 static ID id_writable_p;
71 static ID id_writable_real_p;
72 static ID id_write;
73 static ID id_zero_p;
74 
75 static VALUE
get_strpath(VALUE obj)76 get_strpath(VALUE obj)
77 {
78     VALUE strpath;
79     strpath = rb_ivar_get(obj, id_at_path);
80     if (!RB_TYPE_P(strpath, T_STRING))
81         rb_raise(rb_eTypeError, "unexpected @path");
82     return strpath;
83 }
84 
85 static void
set_strpath(VALUE obj,VALUE val)86 set_strpath(VALUE obj, VALUE val)
87 {
88     rb_ivar_set(obj, id_at_path, val);
89 }
90 
91 /*
92  * Create a Pathname object from the given String (or String-like object).
93  * If +path+ contains a NULL character (<tt>\0</tt>), an ArgumentError is raised.
94  */
95 static VALUE
path_initialize(VALUE self,VALUE arg)96 path_initialize(VALUE self, VALUE arg)
97 {
98     VALUE str;
99     if (RB_TYPE_P(arg, T_STRING)) {
100         str = arg;
101     }
102     else {
103         str = rb_check_funcall(arg, id_to_path, 0, NULL);
104         if (str == Qundef)
105             str = arg;
106         StringValue(str);
107     }
108     if (memchr(RSTRING_PTR(str), '\0', RSTRING_LEN(str)))
109         rb_raise(rb_eArgError, "pathname contains null byte");
110     str = rb_obj_dup(str);
111 
112     set_strpath(self, str);
113     OBJ_INFECT(self, str);
114     return self;
115 }
116 
117 /*
118  * call-seq:
119  *   pathname.freeze -> obj
120  *
121  * Freezes this Pathname.
122  *
123  * See Object.freeze.
124  */
125 static VALUE
path_freeze(VALUE self)126 path_freeze(VALUE self)
127 {
128     rb_call_super(0, 0);
129     rb_str_freeze(get_strpath(self));
130     return self;
131 }
132 
133 /*
134  * call-seq:
135  *   pathname.taint -> obj
136  *
137  * Taints this Pathname.
138  *
139  * See Object.taint.
140  */
141 static VALUE
path_taint(VALUE self)142 path_taint(VALUE self)
143 {
144     rb_call_super(0, 0);
145     rb_obj_taint(get_strpath(self));
146     return self;
147 }
148 
149 /*
150  * call-seq:
151  *   pathname.untaint -> obj
152  *
153  * Untaints this Pathname.
154  *
155  * See Object.untaint.
156  */
157 static VALUE
path_untaint(VALUE self)158 path_untaint(VALUE self)
159 {
160     rb_call_super(0, 0);
161     rb_obj_untaint(get_strpath(self));
162     return self;
163 }
164 
165 /*
166  *  Compare this pathname with +other+.  The comparison is string-based.
167  *  Be aware that two different paths (<tt>foo.txt</tt> and <tt>./foo.txt</tt>)
168  *  can refer to the same file.
169  */
170 static VALUE
path_eq(VALUE self,VALUE other)171 path_eq(VALUE self, VALUE other)
172 {
173     if (!rb_obj_is_kind_of(other, rb_cPathname))
174         return Qfalse;
175     return rb_str_equal(get_strpath(self), get_strpath(other));
176 }
177 
178 /*
179  *  Provides a case-sensitive comparison operator for pathnames.
180  *
181  *	Pathname.new('/usr') <=> Pathname.new('/usr/bin')
182  *	    #=> -1
183  *	Pathname.new('/usr/bin') <=> Pathname.new('/usr/bin')
184  *	    #=> 0
185  *	Pathname.new('/usr/bin') <=> Pathname.new('/USR/BIN')
186  *	    #=> 1
187  *
188  *  It will return +-1+, +0+ or +1+ depending on the value of the left argument
189  *  relative to the right argument. Or it will return +nil+ if the arguments
190  *  are not comparable.
191  */
192 static VALUE
path_cmp(VALUE self,VALUE other)193 path_cmp(VALUE self, VALUE other)
194 {
195     VALUE s1, s2;
196     char *p1, *p2;
197     char *e1, *e2;
198     if (!rb_obj_is_kind_of(other, rb_cPathname))
199         return Qnil;
200     s1 = get_strpath(self);
201     s2 = get_strpath(other);
202     p1 = RSTRING_PTR(s1);
203     p2 = RSTRING_PTR(s2);
204     e1 = p1 + RSTRING_LEN(s1);
205     e2 = p2 + RSTRING_LEN(s2);
206     while (p1 < e1 && p2 < e2) {
207         int c1, c2;
208         c1 = (unsigned char)*p1++;
209         c2 = (unsigned char)*p2++;
210         if (c1 == '/') c1 = '\0';
211         if (c2 == '/') c2 = '\0';
212         if (c1 != c2) {
213             if (c1 < c2)
214                 return INT2FIX(-1);
215             else
216                 return INT2FIX(1);
217         }
218     }
219     if (p1 < e1)
220         return INT2FIX(1);
221     if (p2 < e2)
222         return INT2FIX(-1);
223     return INT2FIX(0);
224 }
225 
226 #ifndef ST2FIX
227 #define ST2FIX(h) LONG2FIX((long)(h))
228 #endif
229 
230 /* :nodoc: */
231 static VALUE
path_hash(VALUE self)232 path_hash(VALUE self)
233 {
234     return ST2FIX(rb_str_hash(get_strpath(self)));
235 }
236 
237 /*
238  *  call-seq:
239  *    pathname.to_s             -> string
240  *    pathname.to_path          -> string
241  *
242  *  Return the path as a String.
243  *
244  *  to_path is implemented so Pathname objects are usable with File.open, etc.
245  */
246 static VALUE
path_to_s(VALUE self)247 path_to_s(VALUE self)
248 {
249     return rb_obj_dup(get_strpath(self));
250 }
251 
252 /* :nodoc: */
253 static VALUE
path_inspect(VALUE self)254 path_inspect(VALUE self)
255 {
256     const char *c = rb_obj_classname(self);
257     VALUE str = get_strpath(self);
258     return rb_sprintf("#<%s:%"PRIsVALUE">", c, str);
259 }
260 
261 /*
262  * Return a pathname which is substituted by String#sub.
263  *
264  *	path1 = Pathname.new('/usr/bin/perl')
265  *	path1.sub('perl', 'ruby')
266  *	    #=> #<Pathname:/usr/bin/ruby>
267  */
268 static VALUE
path_sub(int argc,VALUE * argv,VALUE self)269 path_sub(int argc, VALUE *argv, VALUE self)
270 {
271     VALUE str = get_strpath(self);
272 
273     if (rb_block_given_p()) {
274         str = rb_block_call(str, id_sub, argc, argv, 0, 0);
275     }
276     else {
277         str = rb_funcallv(str, id_sub, argc, argv);
278     }
279     return rb_class_new_instance(1, &str, rb_obj_class(self));
280 }
281 
282 /*
283  * Return a pathname with +repl+ added as a suffix to the basename.
284  *
285  * If self has no extension part, +repl+ is appended.
286  *
287  *	Pathname.new('/usr/bin/shutdown').sub_ext('.rb')
288  *	    #=> #<Pathname:/usr/bin/shutdown.rb>
289  */
290 static VALUE
path_sub_ext(VALUE self,VALUE repl)291 path_sub_ext(VALUE self, VALUE repl)
292 {
293     VALUE str = get_strpath(self);
294     VALUE str2;
295     long extlen;
296     const char *ext;
297     const char *p;
298 
299     StringValue(repl);
300     p = RSTRING_PTR(str);
301     extlen = RSTRING_LEN(str);
302     ext = ruby_enc_find_extname(p, &extlen, rb_enc_get(str));
303     if (ext == NULL) {
304         ext = p + RSTRING_LEN(str);
305     }
306     else if (extlen <= 1) {
307         ext += extlen;
308     }
309     str2 = rb_str_subseq(str, 0, ext-p);
310     rb_str_append(str2, repl);
311     OBJ_INFECT(str2, str);
312     return rb_class_new_instance(1, &str2, rb_obj_class(self));
313 }
314 
315 /* Facade for File */
316 
317 /*
318  * Returns the real (absolute) pathname for +self+ in the actual
319  * filesystem.
320  *
321  * Does not contain symlinks or useless dots, +..+ and +.+.
322  *
323  * All components of the pathname must exist when this method is
324  * called.
325  *
326  */
327 static VALUE
path_realpath(int argc,VALUE * argv,VALUE self)328 path_realpath(int argc, VALUE *argv, VALUE self)
329 {
330     VALUE basedir, str;
331     rb_scan_args(argc, argv, "01", &basedir);
332     str = rb_funcall(rb_cFile, id_realpath, 2, get_strpath(self), basedir);
333     return rb_class_new_instance(1, &str, rb_obj_class(self));
334 }
335 
336 /*
337  * Returns the real (absolute) pathname of +self+ in the actual filesystem.
338  *
339  * Does not contain symlinks or useless dots, +..+ and +.+.
340  *
341  * The last component of the real pathname can be nonexistent.
342  */
343 static VALUE
path_realdirpath(int argc,VALUE * argv,VALUE self)344 path_realdirpath(int argc, VALUE *argv, VALUE self)
345 {
346     VALUE basedir, str;
347     rb_scan_args(argc, argv, "01", &basedir);
348     str = rb_funcall(rb_cFile, id_realdirpath, 2, get_strpath(self), basedir);
349     return rb_class_new_instance(1, &str, rb_obj_class(self));
350 }
351 
352 /*
353  * call-seq:
354  *   pathname.each_line {|line| ... }
355  *   pathname.each_line(sep=$/ [, open_args]) {|line| block }     -> nil
356  *   pathname.each_line(limit [, open_args]) {|line| block }      -> nil
357  *   pathname.each_line(sep, limit [, open_args]) {|line| block } -> nil
358  *   pathname.each_line(...)                                      -> an_enumerator
359  *
360  * Iterates over each line in the file and yields a String object for each.
361  */
362 static VALUE
path_each_line(int argc,VALUE * argv,VALUE self)363 path_each_line(int argc, VALUE *argv, VALUE self)
364 {
365     VALUE args[4];
366     int n;
367 
368     args[0] = get_strpath(self);
369     n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
370     if (rb_block_given_p()) {
371         return rb_block_call(rb_cFile, id_foreach, 1+n, args, 0, 0);
372     }
373     else {
374         return rb_funcallv(rb_cFile, id_foreach, 1+n, args);
375     }
376 }
377 
378 /*
379  * call-seq:
380  *   pathname.read([length [, offset]]) -> string
381  *   pathname.read([length [, offset]], open_args) -> string
382  *
383  * Returns all data from the file, or the first +N+ bytes if specified.
384  *
385  * See File.read.
386  *
387  */
388 static VALUE
path_read(int argc,VALUE * argv,VALUE self)389 path_read(int argc, VALUE *argv, VALUE self)
390 {
391     VALUE args[4];
392     int n;
393 
394     args[0] = get_strpath(self);
395     n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
396     return rb_funcallv(rb_cFile, id_read, 1+n, args);
397 }
398 
399 /*
400  * call-seq:
401  *   pathname.binread([length [, offset]]) -> string
402  *
403  * Returns all the bytes from the file, or the first +N+ if specified.
404  *
405  * See File.binread.
406  *
407  */
408 static VALUE
path_binread(int argc,VALUE * argv,VALUE self)409 path_binread(int argc, VALUE *argv, VALUE self)
410 {
411     VALUE args[3];
412     int n;
413 
414     args[0] = get_strpath(self);
415     n = rb_scan_args(argc, argv, "02", &args[1], &args[2]);
416     return rb_funcallv(rb_cFile, id_binread, 1+n, args);
417 }
418 
419 /*
420  * call-seq:
421  *   pathname.write(string, [offset] )   => fixnum
422  *   pathname.write(string, [offset], open_args )   => fixnum
423  *
424  * Writes +contents+ to the file.
425  *
426  * See File.write.
427  *
428  */
429 static VALUE
path_write(int argc,VALUE * argv,VALUE self)430 path_write(int argc, VALUE *argv, VALUE self)
431 {
432     VALUE args[4];
433     int n;
434 
435     args[0] = get_strpath(self);
436     n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
437     return rb_funcallv(rb_cFile, id_write, 1+n, args);
438 }
439 
440 /*
441  * call-seq:
442  *   pathname.binwrite(string, [offset] )   => fixnum
443  *   pathname.binwrite(string, [offset], open_args )   => fixnum
444  *
445  * Writes +contents+ to the file, opening it in binary mode.
446  *
447  * See File.binwrite.
448  *
449  */
450 static VALUE
path_binwrite(int argc,VALUE * argv,VALUE self)451 path_binwrite(int argc, VALUE *argv, VALUE self)
452 {
453     VALUE args[4];
454     int n;
455 
456     args[0] = get_strpath(self);
457     n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
458     return rb_funcallv(rb_cFile, id_binwrite, 1+n, args);
459 }
460 
461 /*
462  * call-seq:
463  *   pathname.readlines(sep=$/ [, open_args])     -> array
464  *   pathname.readlines(limit [, open_args])      -> array
465  *   pathname.readlines(sep, limit [, open_args]) -> array
466  *
467  * Returns all the lines from the file.
468  *
469  * See File.readlines.
470  *
471  */
472 static VALUE
path_readlines(int argc,VALUE * argv,VALUE self)473 path_readlines(int argc, VALUE *argv, VALUE self)
474 {
475     VALUE args[4];
476     int n;
477 
478     args[0] = get_strpath(self);
479     n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
480     return rb_funcallv(rb_cFile, id_readlines, 1+n, args);
481 }
482 
483 /*
484  * call-seq:
485  *   pathname.sysopen([mode, [perm]])  -> fixnum
486  *
487  * See IO.sysopen.
488  *
489  */
490 static VALUE
path_sysopen(int argc,VALUE * argv,VALUE self)491 path_sysopen(int argc, VALUE *argv, VALUE self)
492 {
493     VALUE args[3];
494     int n;
495 
496     args[0] = get_strpath(self);
497     n = rb_scan_args(argc, argv, "02", &args[1], &args[2]);
498     return rb_funcallv(rb_cIO, id_sysopen, 1+n, args);
499 }
500 
501 /*
502  * call-seq:
503  *   pathname.atime	-> time
504  *
505  * Returns the last access time for the file.
506  *
507  * See File.atime.
508  */
509 static VALUE
path_atime(VALUE self)510 path_atime(VALUE self)
511 {
512     return rb_funcall(rb_cFile, id_atime, 1, get_strpath(self));
513 }
514 
515 #if defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC) || defined(_WIN32)
516 /*
517  * call-seq:
518  *   pathname.birthtime	-> time
519  *
520  * Returns the birth time for the file.
521  * If the platform doesn't have birthtime, raises NotImplementedError.
522  *
523  * See File.birthtime.
524  */
525 static VALUE
path_birthtime(VALUE self)526 path_birthtime(VALUE self)
527 {
528     return rb_funcall(rb_cFile, id_birthtime, 1, get_strpath(self));
529 }
530 #else
531 # define path_birthtime rb_f_notimplement
532 #endif
533 
534 /*
535  * call-seq:
536  *   pathname.ctime	-> time
537  *
538  * Returns the last change time, using directory information, not the file itself.
539  *
540  * See File.ctime.
541  */
542 static VALUE
path_ctime(VALUE self)543 path_ctime(VALUE self)
544 {
545     return rb_funcall(rb_cFile, id_ctime, 1, get_strpath(self));
546 }
547 
548 /*
549  * call-seq:
550  *   pathname.mtime	-> time
551  *
552  * Returns the last modified time of the file.
553  *
554  * See File.mtime.
555  */
556 static VALUE
path_mtime(VALUE self)557 path_mtime(VALUE self)
558 {
559     return rb_funcall(rb_cFile, id_mtime, 1, get_strpath(self));
560 }
561 
562 /*
563  * call-seq:
564  *   pathname.chmod	-> integer
565  *
566  * Changes file permissions.
567  *
568  * See File.chmod.
569  */
570 static VALUE
path_chmod(VALUE self,VALUE mode)571 path_chmod(VALUE self, VALUE mode)
572 {
573     return rb_funcall(rb_cFile, id_chmod, 2, mode, get_strpath(self));
574 }
575 
576 /*
577  * call-seq:
578  *   pathname.lchmod	-> integer
579  *
580  * Same as Pathname.chmod, but does not follow symbolic links.
581  *
582  * See File.lchmod.
583  */
584 static VALUE
path_lchmod(VALUE self,VALUE mode)585 path_lchmod(VALUE self, VALUE mode)
586 {
587     return rb_funcall(rb_cFile, id_lchmod, 2, mode, get_strpath(self));
588 }
589 
590 /*
591  * call-seq:
592  *   pathname.chown	-> integer
593  *
594  * Change owner and group of the file.
595  *
596  * See File.chown.
597  */
598 static VALUE
path_chown(VALUE self,VALUE owner,VALUE group)599 path_chown(VALUE self, VALUE owner, VALUE group)
600 {
601     return rb_funcall(rb_cFile, id_chown, 3, owner, group, get_strpath(self));
602 }
603 
604 /*
605  * call-seq:
606  *   pathname.lchown	-> integer
607  *
608  * Same as Pathname.chown, but does not follow symbolic links.
609  *
610  * See File.lchown.
611  */
612 static VALUE
path_lchown(VALUE self,VALUE owner,VALUE group)613 path_lchown(VALUE self, VALUE owner, VALUE group)
614 {
615     return rb_funcall(rb_cFile, id_lchown, 3, owner, group, get_strpath(self));
616 }
617 
618 /*
619  * call-seq:
620  *    pathname.fnmatch(pattern, [flags])        -> string
621  *    pathname.fnmatch?(pattern, [flags])       -> string
622  *
623  * Return +true+ if the receiver matches the given pattern.
624  *
625  * See File.fnmatch.
626  */
627 static VALUE
path_fnmatch(int argc,VALUE * argv,VALUE self)628 path_fnmatch(int argc, VALUE *argv, VALUE self)
629 {
630     VALUE str = get_strpath(self);
631     VALUE pattern, flags;
632     if (rb_scan_args(argc, argv, "11", &pattern, &flags) == 1)
633         return rb_funcall(rb_cFile, id_fnmatch, 2, pattern, str);
634     else
635         return rb_funcall(rb_cFile, id_fnmatch, 3, pattern, str, flags);
636 }
637 
638 /*
639  * call-seq:
640  *   pathname.ftype	-> string
641  *
642  * Returns "type" of file ("file", "directory", etc).
643  *
644  * See File.ftype.
645  */
646 static VALUE
path_ftype(VALUE self)647 path_ftype(VALUE self)
648 {
649     return rb_funcall(rb_cFile, id_ftype, 1, get_strpath(self));
650 }
651 
652 /*
653  * call-seq:
654  *   pathname.make_link(old)
655  *
656  * Creates a hard link at _pathname_.
657  *
658  * See File.link.
659  */
660 static VALUE
path_make_link(VALUE self,VALUE old)661 path_make_link(VALUE self, VALUE old)
662 {
663     return rb_funcall(rb_cFile, id_link, 2, old, get_strpath(self));
664 }
665 
666 /*
667  * Opens the file for reading or writing.
668  *
669  * See File.open.
670  */
671 static VALUE
path_open(int argc,VALUE * argv,VALUE self)672 path_open(int argc, VALUE *argv, VALUE self)
673 {
674     VALUE args[4];
675     int n;
676 
677     args[0] = get_strpath(self);
678     n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
679     if (rb_block_given_p()) {
680         return rb_block_call(rb_cFile, id_open, 1+n, args, 0, 0);
681     }
682     else {
683         return rb_funcallv(rb_cFile, id_open, 1+n, args);
684     }
685 }
686 
687 /*
688  * Read symbolic link.
689  *
690  * See File.readlink.
691  */
692 static VALUE
path_readlink(VALUE self)693 path_readlink(VALUE self)
694 {
695     VALUE str;
696     str = rb_funcall(rb_cFile, id_readlink, 1, get_strpath(self));
697     return rb_class_new_instance(1, &str, rb_obj_class(self));
698 }
699 
700 /*
701  * Rename the file.
702  *
703  * See File.rename.
704  */
705 static VALUE
path_rename(VALUE self,VALUE to)706 path_rename(VALUE self, VALUE to)
707 {
708     return rb_funcall(rb_cFile, id_rename, 2, get_strpath(self), to);
709 }
710 
711 /*
712  * Returns a File::Stat object.
713  *
714  * See File.stat.
715  */
716 static VALUE
path_stat(VALUE self)717 path_stat(VALUE self)
718 {
719     return rb_funcall(rb_cFile, id_stat, 1, get_strpath(self));
720 }
721 
722 /*
723  * See File.lstat.
724  */
725 static VALUE
path_lstat(VALUE self)726 path_lstat(VALUE self)
727 {
728     return rb_funcall(rb_cFile, id_lstat, 1, get_strpath(self));
729 }
730 
731 /*
732  * call-seq:
733  *   pathname.make_symlink(old)
734  *
735  * Creates a symbolic link.
736  *
737  * See File.symlink.
738  */
739 static VALUE
path_make_symlink(VALUE self,VALUE old)740 path_make_symlink(VALUE self, VALUE old)
741 {
742     return rb_funcall(rb_cFile, id_symlink, 2, old, get_strpath(self));
743 }
744 
745 /*
746  * Truncates the file to +length+ bytes.
747  *
748  * See File.truncate.
749  */
750 static VALUE
path_truncate(VALUE self,VALUE length)751 path_truncate(VALUE self, VALUE length)
752 {
753     return rb_funcall(rb_cFile, id_truncate, 2, get_strpath(self), length);
754 }
755 
756 /*
757  * Update the access and modification times of the file.
758  *
759  * See File.utime.
760  */
761 static VALUE
path_utime(VALUE self,VALUE atime,VALUE mtime)762 path_utime(VALUE self, VALUE atime, VALUE mtime)
763 {
764     return rb_funcall(rb_cFile, id_utime, 3, atime, mtime, get_strpath(self));
765 }
766 
767 /*
768  * Returns the last component of the path.
769  *
770  * See File.basename.
771  */
772 static VALUE
path_basename(int argc,VALUE * argv,VALUE self)773 path_basename(int argc, VALUE *argv, VALUE self)
774 {
775     VALUE str = get_strpath(self);
776     VALUE fext;
777     if (rb_scan_args(argc, argv, "01", &fext) == 0)
778         str = rb_funcall(rb_cFile, id_basename, 1, str);
779     else
780         str = rb_funcall(rb_cFile, id_basename, 2, str, fext);
781     return rb_class_new_instance(1, &str, rb_obj_class(self));
782 }
783 
784 /*
785  * Returns all but the last component of the path.
786  *
787  * See File.dirname.
788  */
789 static VALUE
path_dirname(VALUE self)790 path_dirname(VALUE self)
791 {
792     VALUE str = get_strpath(self);
793     str = rb_funcall(rb_cFile, id_dirname, 1, str);
794     return rb_class_new_instance(1, &str, rb_obj_class(self));
795 }
796 
797 /*
798  * Returns the file's extension.
799  *
800  * See File.extname.
801  */
802 static VALUE
path_extname(VALUE self)803 path_extname(VALUE self)
804 {
805     VALUE str = get_strpath(self);
806     return rb_funcall(rb_cFile, id_extname, 1, str);
807 }
808 
809 /*
810  * Returns the absolute path for the file.
811  *
812  * See File.expand_path.
813  */
814 static VALUE
path_expand_path(int argc,VALUE * argv,VALUE self)815 path_expand_path(int argc, VALUE *argv, VALUE self)
816 {
817     VALUE str = get_strpath(self);
818     VALUE dname;
819     if (rb_scan_args(argc, argv, "01", &dname) == 0)
820         str = rb_funcall(rb_cFile, id_expand_path, 1, str);
821     else
822         str = rb_funcall(rb_cFile, id_expand_path, 2, str, dname);
823     return rb_class_new_instance(1, &str, rb_obj_class(self));
824 }
825 
826 /*
827  * Returns the #dirname and the #basename in an Array.
828  *
829  * See File.split.
830  */
831 static VALUE
path_split(VALUE self)832 path_split(VALUE self)
833 {
834     VALUE str = get_strpath(self);
835     VALUE ary, dirname, basename;
836     ary = rb_funcall(rb_cFile, id_split, 1, str);
837     ary = rb_check_array_type(ary);
838     dirname = rb_ary_entry(ary, 0);
839     basename = rb_ary_entry(ary, 1);
840     dirname = rb_class_new_instance(1, &dirname, rb_obj_class(self));
841     basename = rb_class_new_instance(1, &basename, rb_obj_class(self));
842     return rb_ary_new3(2, dirname, basename);
843 }
844 
845 /*
846  * See FileTest.blockdev?.
847  */
848 static VALUE
path_blockdev_p(VALUE self)849 path_blockdev_p(VALUE self)
850 {
851     return rb_funcall(rb_mFileTest, id_blockdev_p, 1, get_strpath(self));
852 }
853 
854 /*
855  * See FileTest.chardev?.
856  */
857 static VALUE
path_chardev_p(VALUE self)858 path_chardev_p(VALUE self)
859 {
860     return rb_funcall(rb_mFileTest, id_chardev_p, 1, get_strpath(self));
861 }
862 
863 /*
864  * See FileTest.executable?.
865  */
866 static VALUE
path_executable_p(VALUE self)867 path_executable_p(VALUE self)
868 {
869     return rb_funcall(rb_mFileTest, id_executable_p, 1, get_strpath(self));
870 }
871 
872 /*
873  * See FileTest.executable_real?.
874  */
875 static VALUE
path_executable_real_p(VALUE self)876 path_executable_real_p(VALUE self)
877 {
878     return rb_funcall(rb_mFileTest, id_executable_real_p, 1, get_strpath(self));
879 }
880 
881 /*
882  * See FileTest.exist?.
883  */
884 static VALUE
path_exist_p(VALUE self)885 path_exist_p(VALUE self)
886 {
887     return rb_funcall(rb_mFileTest, id_exist_p, 1, get_strpath(self));
888 }
889 
890 /*
891  * See FileTest.grpowned?.
892  */
893 static VALUE
path_grpowned_p(VALUE self)894 path_grpowned_p(VALUE self)
895 {
896     return rb_funcall(rb_mFileTest, id_grpowned_p, 1, get_strpath(self));
897 }
898 
899 /*
900  * See FileTest.directory?.
901  */
902 static VALUE
path_directory_p(VALUE self)903 path_directory_p(VALUE self)
904 {
905     return rb_funcall(rb_mFileTest, id_directory_p, 1, get_strpath(self));
906 }
907 
908 /*
909  * See FileTest.file?.
910  */
911 static VALUE
path_file_p(VALUE self)912 path_file_p(VALUE self)
913 {
914     return rb_funcall(rb_mFileTest, id_file_p, 1, get_strpath(self));
915 }
916 
917 /*
918  * See FileTest.pipe?.
919  */
920 static VALUE
path_pipe_p(VALUE self)921 path_pipe_p(VALUE self)
922 {
923     return rb_funcall(rb_mFileTest, id_pipe_p, 1, get_strpath(self));
924 }
925 
926 /*
927  * See FileTest.socket?.
928  */
929 static VALUE
path_socket_p(VALUE self)930 path_socket_p(VALUE self)
931 {
932     return rb_funcall(rb_mFileTest, id_socket_p, 1, get_strpath(self));
933 }
934 
935 /*
936  * See FileTest.owned?.
937  */
938 static VALUE
path_owned_p(VALUE self)939 path_owned_p(VALUE self)
940 {
941     return rb_funcall(rb_mFileTest, id_owned_p, 1, get_strpath(self));
942 }
943 
944 /*
945  * See FileTest.readable?.
946  */
947 static VALUE
path_readable_p(VALUE self)948 path_readable_p(VALUE self)
949 {
950     return rb_funcall(rb_mFileTest, id_readable_p, 1, get_strpath(self));
951 }
952 
953 /*
954  * See FileTest.world_readable?.
955  */
956 static VALUE
path_world_readable_p(VALUE self)957 path_world_readable_p(VALUE self)
958 {
959     return rb_funcall(rb_mFileTest, id_world_readable_p, 1, get_strpath(self));
960 }
961 
962 /*
963  * See FileTest.readable_real?.
964  */
965 static VALUE
path_readable_real_p(VALUE self)966 path_readable_real_p(VALUE self)
967 {
968     return rb_funcall(rb_mFileTest, id_readable_real_p, 1, get_strpath(self));
969 }
970 
971 /*
972  * See FileTest.setuid?.
973  */
974 static VALUE
path_setuid_p(VALUE self)975 path_setuid_p(VALUE self)
976 {
977     return rb_funcall(rb_mFileTest, id_setuid_p, 1, get_strpath(self));
978 }
979 
980 /*
981  * See FileTest.setgid?.
982  */
983 static VALUE
path_setgid_p(VALUE self)984 path_setgid_p(VALUE self)
985 {
986     return rb_funcall(rb_mFileTest, id_setgid_p, 1, get_strpath(self));
987 }
988 
989 /*
990  * See FileTest.size.
991  */
992 static VALUE
path_size(VALUE self)993 path_size(VALUE self)
994 {
995     return rb_funcall(rb_mFileTest, id_size, 1, get_strpath(self));
996 }
997 
998 /*
999  * See FileTest.size?.
1000  */
1001 static VALUE
path_size_p(VALUE self)1002 path_size_p(VALUE self)
1003 {
1004     return rb_funcall(rb_mFileTest, id_size_p, 1, get_strpath(self));
1005 }
1006 
1007 /*
1008  * See FileTest.sticky?.
1009  */
1010 static VALUE
path_sticky_p(VALUE self)1011 path_sticky_p(VALUE self)
1012 {
1013     return rb_funcall(rb_mFileTest, id_sticky_p, 1, get_strpath(self));
1014 }
1015 
1016 /*
1017  * See FileTest.symlink?.
1018  */
1019 static VALUE
path_symlink_p(VALUE self)1020 path_symlink_p(VALUE self)
1021 {
1022     return rb_funcall(rb_mFileTest, id_symlink_p, 1, get_strpath(self));
1023 }
1024 
1025 /*
1026  * See FileTest.writable?.
1027  */
1028 static VALUE
path_writable_p(VALUE self)1029 path_writable_p(VALUE self)
1030 {
1031     return rb_funcall(rb_mFileTest, id_writable_p, 1, get_strpath(self));
1032 }
1033 
1034 /*
1035  * See FileTest.world_writable?.
1036  */
1037 static VALUE
path_world_writable_p(VALUE self)1038 path_world_writable_p(VALUE self)
1039 {
1040     return rb_funcall(rb_mFileTest, id_world_writable_p, 1, get_strpath(self));
1041 }
1042 
1043 /*
1044  * See FileTest.writable_real?.
1045  */
1046 static VALUE
path_writable_real_p(VALUE self)1047 path_writable_real_p(VALUE self)
1048 {
1049     return rb_funcall(rb_mFileTest, id_writable_real_p, 1, get_strpath(self));
1050 }
1051 
1052 /*
1053  * See FileTest.zero?.
1054  */
1055 static VALUE
path_zero_p(VALUE self)1056 path_zero_p(VALUE self)
1057 {
1058     return rb_funcall(rb_mFileTest, id_zero_p, 1, get_strpath(self));
1059 }
1060 
1061 /*
1062  * Tests the file is empty.
1063  *
1064  * See Dir#empty? and FileTest.empty?.
1065  */
1066 static VALUE
path_empty_p(VALUE self)1067 path_empty_p(VALUE self)
1068 {
1069 
1070     VALUE path = get_strpath(self);
1071     if (RTEST(rb_funcall(rb_mFileTest, id_directory_p, 1, path)))
1072         return rb_funcall(rb_cDir, id_empty_p, 1, path);
1073     else
1074         return rb_funcall(rb_mFileTest, id_empty_p, 1, path);
1075 }
1076 
1077 static VALUE
s_glob_i(RB_BLOCK_CALL_FUNC_ARGLIST (elt,klass))1078 s_glob_i(RB_BLOCK_CALL_FUNC_ARGLIST(elt, klass))
1079 {
1080     return rb_yield(rb_class_new_instance(1, &elt, klass));
1081 }
1082 
1083 /*
1084  * Returns or yields Pathname objects.
1085  *
1086  *  Pathname.glob("lib/i*.rb")
1087  *	#=> [#<Pathname:lib/ipaddr.rb>, #<Pathname:lib/irb.rb>]
1088  *
1089  * See Dir.glob.
1090  */
1091 static VALUE
path_s_glob(int argc,VALUE * argv,VALUE klass)1092 path_s_glob(int argc, VALUE *argv, VALUE klass)
1093 {
1094     VALUE args[2];
1095     int n;
1096 
1097     n = rb_scan_args(argc, argv, "11", &args[0], &args[1]);
1098     if (rb_block_given_p()) {
1099         return rb_block_call(rb_cDir, id_glob, n, args, s_glob_i, klass);
1100     }
1101     else {
1102         VALUE ary;
1103         long i;
1104         ary = rb_funcallv(rb_cDir, id_glob, n, args);
1105         ary = rb_convert_type(ary, T_ARRAY, "Array", "to_ary");
1106         for (i = 0; i < RARRAY_LEN(ary); i++) {
1107             VALUE elt = RARRAY_AREF(ary, i);
1108             elt = rb_class_new_instance(1, &elt, klass);
1109             rb_ary_store(ary, i, elt);
1110         }
1111         return ary;
1112     }
1113 }
1114 
1115 static VALUE
glob_i(RB_BLOCK_CALL_FUNC_ARGLIST (elt,self))1116 glob_i(RB_BLOCK_CALL_FUNC_ARGLIST(elt, self))
1117 {
1118     elt = rb_funcall(self, '+', 1, elt);
1119     return rb_yield(elt);
1120 }
1121 
1122 /*
1123  * Returns or yields Pathname objects.
1124  *
1125  *  Pathname("ruby-2.4.2").glob("R*.md")
1126  *  #=> [#<Pathname:ruby-2.4.2/README.md>, #<Pathname:ruby-2.4.2/README.ja.md>]
1127  *
1128  * See Dir.glob.
1129  * This method uses the +base+ keyword argument of Dir.glob.
1130  */
1131 static VALUE
path_glob(int argc,VALUE * argv,VALUE self)1132 path_glob(int argc, VALUE *argv, VALUE self)
1133 {
1134     VALUE args[3];
1135     int n;
1136 
1137     n = rb_scan_args(argc, argv, "11", &args[0], &args[1]);
1138     if (n == 1)
1139       args[1] = INT2FIX(0);
1140 
1141     args[2] = rb_hash_new();
1142     rb_hash_aset(args[2], ID2SYM(id_base), get_strpath(self));
1143 
1144     n = 3;
1145 
1146     if (rb_block_given_p()) {
1147         return rb_block_call(rb_cDir, id_glob, n, args, glob_i, self);
1148     }
1149     else {
1150         VALUE ary;
1151         long i;
1152         ary = rb_funcallv(rb_cDir, id_glob, n, args);
1153         ary = rb_convert_type(ary, T_ARRAY, "Array", "to_ary");
1154         for (i = 0; i < RARRAY_LEN(ary); i++) {
1155             VALUE elt = RARRAY_AREF(ary, i);
1156             elt = rb_funcall(self, '+', 1, elt);
1157             rb_ary_store(ary, i, elt);
1158         }
1159         return ary;
1160     }
1161 }
1162 
1163 /*
1164  * Returns the current working directory as a Pathname.
1165  *
1166  *	Pathname.getwd
1167  *	    #=> #<Pathname:/home/zzak/projects/ruby>
1168  *
1169  * See Dir.getwd.
1170  */
1171 static VALUE
path_s_getwd(VALUE klass)1172 path_s_getwd(VALUE klass)
1173 {
1174     VALUE str;
1175     str = rb_funcall(rb_cDir, id_getwd, 0);
1176     return rb_class_new_instance(1, &str, klass);
1177 }
1178 
1179 /*
1180  * Return the entries (files and subdirectories) in the directory, each as a
1181  * Pathname object.
1182  *
1183  * The results contains just the names in the directory, without any trailing
1184  * slashes or recursive look-up.
1185  *
1186  *   pp Pathname.new('/usr/local').entries
1187  *   #=> [#<Pathname:share>,
1188  *   #    #<Pathname:lib>,
1189  *   #    #<Pathname:..>,
1190  *   #    #<Pathname:include>,
1191  *   #    #<Pathname:etc>,
1192  *   #    #<Pathname:bin>,
1193  *   #    #<Pathname:man>,
1194  *   #    #<Pathname:games>,
1195  *   #    #<Pathname:.>,
1196  *   #    #<Pathname:sbin>,
1197  *   #    #<Pathname:src>]
1198  *
1199  * The result may contain the current directory <code>#<Pathname:.></code> and
1200  * the parent directory <code>#<Pathname:..></code>.
1201  *
1202  * If you don't want +.+ and +..+ and
1203  * want directories, consider Pathname#children.
1204  */
1205 static VALUE
path_entries(VALUE self)1206 path_entries(VALUE self)
1207 {
1208     VALUE klass, str, ary;
1209     long i;
1210     klass = rb_obj_class(self);
1211     str = get_strpath(self);
1212     ary = rb_funcall(rb_cDir, id_entries, 1, str);
1213     ary = rb_convert_type(ary, T_ARRAY, "Array", "to_ary");
1214     for (i = 0; i < RARRAY_LEN(ary); i++) {
1215 	VALUE elt = RARRAY_AREF(ary, i);
1216         elt = rb_class_new_instance(1, &elt, klass);
1217         rb_ary_store(ary, i, elt);
1218     }
1219     return ary;
1220 }
1221 
1222 /*
1223  * Create the referenced directory.
1224  *
1225  * See Dir.mkdir.
1226  */
1227 static VALUE
path_mkdir(int argc,VALUE * argv,VALUE self)1228 path_mkdir(int argc, VALUE *argv, VALUE self)
1229 {
1230     VALUE str = get_strpath(self);
1231     VALUE vmode;
1232     if (rb_scan_args(argc, argv, "01", &vmode) == 0)
1233         return rb_funcall(rb_cDir, id_mkdir, 1, str);
1234     else
1235         return rb_funcall(rb_cDir, id_mkdir, 2, str, vmode);
1236 }
1237 
1238 /*
1239  * Remove the referenced directory.
1240  *
1241  * See Dir.rmdir.
1242  */
1243 static VALUE
path_rmdir(VALUE self)1244 path_rmdir(VALUE self)
1245 {
1246     return rb_funcall(rb_cDir, id_rmdir, 1, get_strpath(self));
1247 }
1248 
1249 /*
1250  * Opens the referenced directory.
1251  *
1252  * See Dir.open.
1253  */
1254 static VALUE
path_opendir(VALUE self)1255 path_opendir(VALUE self)
1256 {
1257     VALUE args[1];
1258 
1259     args[0] = get_strpath(self);
1260     return rb_block_call(rb_cDir, id_open, 1, args, 0, 0);
1261 }
1262 
1263 static VALUE
each_entry_i(RB_BLOCK_CALL_FUNC_ARGLIST (elt,klass))1264 each_entry_i(RB_BLOCK_CALL_FUNC_ARGLIST(elt, klass))
1265 {
1266     return rb_yield(rb_class_new_instance(1, &elt, klass));
1267 }
1268 
1269 /*
1270  * Iterates over the entries (files and subdirectories) in the directory,
1271  * yielding a Pathname object for each entry.
1272  */
1273 static VALUE
path_each_entry(VALUE self)1274 path_each_entry(VALUE self)
1275 {
1276     VALUE args[1];
1277 
1278     args[0] = get_strpath(self);
1279     return rb_block_call(rb_cDir, id_foreach, 1, args, each_entry_i, rb_obj_class(self));
1280 }
1281 
1282 static VALUE
unlink_body(VALUE str)1283 unlink_body(VALUE str)
1284 {
1285     return rb_funcall(rb_cDir, id_unlink, 1, str);
1286 }
1287 
1288 static VALUE
unlink_rescue(VALUE str,VALUE errinfo)1289 unlink_rescue(VALUE str, VALUE errinfo)
1290 {
1291     return rb_funcall(rb_cFile, id_unlink, 1, str);
1292 }
1293 
1294 /*
1295  * Removes a file or directory, using File.unlink if +self+ is a file, or
1296  * Dir.unlink as necessary.
1297  */
1298 static VALUE
path_unlink(VALUE self)1299 path_unlink(VALUE self)
1300 {
1301     VALUE eENOTDIR = rb_const_get_at(rb_mErrno, id_ENOTDIR);
1302     VALUE str = get_strpath(self);
1303     return rb_rescue2(unlink_body, str, unlink_rescue, str, eENOTDIR, (VALUE)0);
1304 }
1305 
1306 /*
1307  * :call-seq:
1308  *  Pathname(path)  -> pathname
1309  *
1310  * Creates a new Pathname object from the given string, +path+, and returns
1311  * pathname object.
1312  *
1313  * In order to use this constructor, you must first require the Pathname
1314  * standard library extension.
1315  *
1316  *	require 'pathname'
1317  *	Pathname("/home/zzak")
1318  *	#=> #<Pathname:/home/zzak>
1319  *
1320  * See also Pathname::new for more information.
1321  */
1322 static VALUE
path_f_pathname(VALUE self,VALUE str)1323 path_f_pathname(VALUE self, VALUE str)
1324 {
1325     return rb_class_new_instance(1, &str, rb_cPathname);
1326 }
1327 
1328 /*
1329  *
1330  * Pathname represents the name of a file or directory on the filesystem,
1331  * but not the file itself.
1332  *
1333  * The pathname depends on the Operating System: Unix, Windows, etc.
1334  * This library works with pathnames of local OS, however non-Unix pathnames
1335  * are supported experimentally.
1336  *
1337  * A Pathname can be relative or absolute.  It's not until you try to
1338  * reference the file that it even matters whether the file exists or not.
1339  *
1340  * Pathname is immutable.  It has no method for destructive update.
1341  *
1342  * The goal of this class is to manipulate file path information in a neater
1343  * way than standard Ruby provides.  The examples below demonstrate the
1344  * difference.
1345  *
1346  * *All* functionality from File, FileTest, and some from Dir and FileUtils is
1347  * included, in an unsurprising way.  It is essentially a facade for all of
1348  * these, and more.
1349  *
1350  * == Examples
1351  *
1352  * === Example 1: Using Pathname
1353  *
1354  *   require 'pathname'
1355  *   pn = Pathname.new("/usr/bin/ruby")
1356  *   size = pn.size              # 27662
1357  *   isdir = pn.directory?       # false
1358  *   dir  = pn.dirname           # Pathname:/usr/bin
1359  *   base = pn.basename          # Pathname:ruby
1360  *   dir, base = pn.split        # [Pathname:/usr/bin, Pathname:ruby]
1361  *   data = pn.read
1362  *   pn.open { |f| _ }
1363  *   pn.each_line { |line| _ }
1364  *
1365  * === Example 2: Using standard Ruby
1366  *
1367  *   pn = "/usr/bin/ruby"
1368  *   size = File.size(pn)        # 27662
1369  *   isdir = File.directory?(pn) # false
1370  *   dir  = File.dirname(pn)     # "/usr/bin"
1371  *   base = File.basename(pn)    # "ruby"
1372  *   dir, base = File.split(pn)  # ["/usr/bin", "ruby"]
1373  *   data = File.read(pn)
1374  *   File.open(pn) { |f| _ }
1375  *   File.foreach(pn) { |line| _ }
1376  *
1377  * === Example 3: Special features
1378  *
1379  *   p1 = Pathname.new("/usr/lib")   # Pathname:/usr/lib
1380  *   p2 = p1 + "ruby/1.8"            # Pathname:/usr/lib/ruby/1.8
1381  *   p3 = p1.parent                  # Pathname:/usr
1382  *   p4 = p2.relative_path_from(p3)  # Pathname:lib/ruby/1.8
1383  *   pwd = Pathname.pwd              # Pathname:/home/gavin
1384  *   pwd.absolute?                   # true
1385  *   p5 = Pathname.new "."           # Pathname:.
1386  *   p5 = p5 + "music/../articles"   # Pathname:music/../articles
1387  *   p5.cleanpath                    # Pathname:articles
1388  *   p5.realpath                     # Pathname:/home/gavin/articles
1389  *   p5.children                     # [Pathname:/home/gavin/articles/linux, ...]
1390  *
1391  * == Breakdown of functionality
1392  *
1393  * === Core methods
1394  *
1395  * These methods are effectively manipulating a String, because that's
1396  * all a path is.  None of these access the file system except for
1397  * #mountpoint?, #children, #each_child, #realdirpath and #realpath.
1398  *
1399  * - +
1400  * - #join
1401  * - #parent
1402  * - #root?
1403  * - #absolute?
1404  * - #relative?
1405  * - #relative_path_from
1406  * - #each_filename
1407  * - #cleanpath
1408  * - #realpath
1409  * - #realdirpath
1410  * - #children
1411  * - #each_child
1412  * - #mountpoint?
1413  *
1414  * === File status predicate methods
1415  *
1416  * These methods are a facade for FileTest:
1417  * - #blockdev?
1418  * - #chardev?
1419  * - #directory?
1420  * - #executable?
1421  * - #executable_real?
1422  * - #exist?
1423  * - #file?
1424  * - #grpowned?
1425  * - #owned?
1426  * - #pipe?
1427  * - #readable?
1428  * - #world_readable?
1429  * - #readable_real?
1430  * - #setgid?
1431  * - #setuid?
1432  * - #size
1433  * - #size?
1434  * - #socket?
1435  * - #sticky?
1436  * - #symlink?
1437  * - #writable?
1438  * - #world_writable?
1439  * - #writable_real?
1440  * - #zero?
1441  *
1442  * === File property and manipulation methods
1443  *
1444  * These methods are a facade for File:
1445  * - #atime
1446  * - #birthtime
1447  * - #ctime
1448  * - #mtime
1449  * - #chmod(mode)
1450  * - #lchmod(mode)
1451  * - #chown(owner, group)
1452  * - #lchown(owner, group)
1453  * - #fnmatch(pattern, *args)
1454  * - #fnmatch?(pattern, *args)
1455  * - #ftype
1456  * - #make_link(old)
1457  * - #open(*args, &block)
1458  * - #readlink
1459  * - #rename(to)
1460  * - #stat
1461  * - #lstat
1462  * - #make_symlink(old)
1463  * - #truncate(length)
1464  * - #utime(atime, mtime)
1465  * - #basename(*args)
1466  * - #dirname
1467  * - #extname
1468  * - #expand_path(*args)
1469  * - #split
1470  *
1471  * === Directory methods
1472  *
1473  * These methods are a facade for Dir:
1474  * - Pathname.glob(*args)
1475  * - Pathname.getwd / Pathname.pwd
1476  * - #rmdir
1477  * - #entries
1478  * - #each_entry(&block)
1479  * - #mkdir(*args)
1480  * - #opendir(*args)
1481  *
1482  * === IO
1483  *
1484  * These methods are a facade for IO:
1485  * - #each_line(*args, &block)
1486  * - #read(*args)
1487  * - #binread(*args)
1488  * - #readlines(*args)
1489  * - #sysopen(*args)
1490  *
1491  * === Utilities
1492  *
1493  * These methods are a mixture of Find, FileUtils, and others:
1494  * - #find(&block)
1495  * - #mkpath
1496  * - #rmtree
1497  * - #unlink / #delete
1498  *
1499  *
1500  * == Method documentation
1501  *
1502  * As the above section shows, most of the methods in Pathname are facades.  The
1503  * documentation for these methods generally just says, for instance, "See
1504  * FileTest.writable?", as you should be familiar with the original method
1505  * anyway, and its documentation (e.g. through +ri+) will contain more
1506  * information.  In some cases, a brief description will follow.
1507  */
1508 void
Init_pathname(void)1509 Init_pathname(void)
1510 {
1511     InitVM(pathname);
1512 
1513     rb_cPathname = rb_define_class("Pathname", rb_cObject);
1514     rb_define_method(rb_cPathname, "initialize", path_initialize, 1);
1515     rb_define_method(rb_cPathname, "freeze", path_freeze, 0);
1516     rb_define_method(rb_cPathname, "taint", path_taint, 0);
1517     rb_define_method(rb_cPathname, "untaint", path_untaint, 0);
1518     rb_define_method(rb_cPathname, "==", path_eq, 1);
1519     rb_define_method(rb_cPathname, "===", path_eq, 1);
1520     rb_define_method(rb_cPathname, "eql?", path_eq, 1);
1521     rb_define_method(rb_cPathname, "<=>", path_cmp, 1);
1522     rb_define_method(rb_cPathname, "hash", path_hash, 0);
1523     rb_define_method(rb_cPathname, "to_s", path_to_s, 0);
1524     rb_define_method(rb_cPathname, "to_path", path_to_s, 0);
1525     rb_define_method(rb_cPathname, "inspect", path_inspect, 0);
1526     rb_define_method(rb_cPathname, "sub", path_sub, -1);
1527     rb_define_method(rb_cPathname, "sub_ext", path_sub_ext, 1);
1528     rb_define_method(rb_cPathname, "realpath", path_realpath, -1);
1529     rb_define_method(rb_cPathname, "realdirpath", path_realdirpath, -1);
1530     rb_define_method(rb_cPathname, "each_line", path_each_line, -1);
1531     rb_define_method(rb_cPathname, "read", path_read, -1);
1532     rb_define_method(rb_cPathname, "binread", path_binread, -1);
1533     rb_define_method(rb_cPathname, "readlines", path_readlines, -1);
1534     rb_define_method(rb_cPathname, "write", path_write, -1);
1535     rb_define_method(rb_cPathname, "binwrite", path_binwrite, -1);
1536     rb_define_method(rb_cPathname, "sysopen", path_sysopen, -1);
1537     rb_define_method(rb_cPathname, "atime", path_atime, 0);
1538     rb_define_method(rb_cPathname, "birthtime", path_birthtime, 0);
1539     rb_define_method(rb_cPathname, "ctime", path_ctime, 0);
1540     rb_define_method(rb_cPathname, "mtime", path_mtime, 0);
1541     rb_define_method(rb_cPathname, "chmod", path_chmod, 1);
1542     rb_define_method(rb_cPathname, "lchmod", path_lchmod, 1);
1543     rb_define_method(rb_cPathname, "chown", path_chown, 2);
1544     rb_define_method(rb_cPathname, "lchown", path_lchown, 2);
1545     rb_define_method(rb_cPathname, "fnmatch", path_fnmatch, -1);
1546     rb_define_method(rb_cPathname, "fnmatch?", path_fnmatch, -1);
1547     rb_define_method(rb_cPathname, "ftype", path_ftype, 0);
1548     rb_define_method(rb_cPathname, "make_link", path_make_link, 1);
1549     rb_define_method(rb_cPathname, "open", path_open, -1);
1550     rb_define_method(rb_cPathname, "readlink", path_readlink, 0);
1551     rb_define_method(rb_cPathname, "rename", path_rename, 1);
1552     rb_define_method(rb_cPathname, "stat", path_stat, 0);
1553     rb_define_method(rb_cPathname, "lstat", path_lstat, 0);
1554     rb_define_method(rb_cPathname, "make_symlink", path_make_symlink, 1);
1555     rb_define_method(rb_cPathname, "truncate", path_truncate, 1);
1556     rb_define_method(rb_cPathname, "utime", path_utime, 2);
1557     rb_define_method(rb_cPathname, "basename", path_basename, -1);
1558     rb_define_method(rb_cPathname, "dirname", path_dirname, 0);
1559     rb_define_method(rb_cPathname, "extname", path_extname, 0);
1560     rb_define_method(rb_cPathname, "expand_path", path_expand_path, -1);
1561     rb_define_method(rb_cPathname, "split", path_split, 0);
1562     rb_define_method(rb_cPathname, "blockdev?", path_blockdev_p, 0);
1563     rb_define_method(rb_cPathname, "chardev?", path_chardev_p, 0);
1564     rb_define_method(rb_cPathname, "executable?", path_executable_p, 0);
1565     rb_define_method(rb_cPathname, "executable_real?", path_executable_real_p, 0);
1566     rb_define_method(rb_cPathname, "exist?", path_exist_p, 0);
1567     rb_define_method(rb_cPathname, "grpowned?", path_grpowned_p, 0);
1568     rb_define_method(rb_cPathname, "directory?", path_directory_p, 0);
1569     rb_define_method(rb_cPathname, "file?", path_file_p, 0);
1570     rb_define_method(rb_cPathname, "pipe?", path_pipe_p, 0);
1571     rb_define_method(rb_cPathname, "socket?", path_socket_p, 0);
1572     rb_define_method(rb_cPathname, "owned?", path_owned_p, 0);
1573     rb_define_method(rb_cPathname, "readable?", path_readable_p, 0);
1574     rb_define_method(rb_cPathname, "world_readable?", path_world_readable_p, 0);
1575     rb_define_method(rb_cPathname, "readable_real?", path_readable_real_p, 0);
1576     rb_define_method(rb_cPathname, "setuid?", path_setuid_p, 0);
1577     rb_define_method(rb_cPathname, "setgid?", path_setgid_p, 0);
1578     rb_define_method(rb_cPathname, "size", path_size, 0);
1579     rb_define_method(rb_cPathname, "size?", path_size_p, 0);
1580     rb_define_method(rb_cPathname, "sticky?", path_sticky_p, 0);
1581     rb_define_method(rb_cPathname, "symlink?", path_symlink_p, 0);
1582     rb_define_method(rb_cPathname, "writable?", path_writable_p, 0);
1583     rb_define_method(rb_cPathname, "world_writable?", path_world_writable_p, 0);
1584     rb_define_method(rb_cPathname, "writable_real?", path_writable_real_p, 0);
1585     rb_define_method(rb_cPathname, "zero?", path_zero_p, 0);
1586     rb_define_method(rb_cPathname, "empty?", path_empty_p, 0);
1587     rb_define_singleton_method(rb_cPathname, "glob", path_s_glob, -1);
1588     rb_define_singleton_method(rb_cPathname, "getwd", path_s_getwd, 0);
1589     rb_define_singleton_method(rb_cPathname, "pwd", path_s_getwd, 0);
1590     rb_define_method(rb_cPathname, "glob", path_glob, -1);
1591     rb_define_method(rb_cPathname, "entries", path_entries, 0);
1592     rb_define_method(rb_cPathname, "mkdir", path_mkdir, -1);
1593     rb_define_method(rb_cPathname, "rmdir", path_rmdir, 0);
1594     rb_define_method(rb_cPathname, "opendir", path_opendir, 0);
1595     rb_define_method(rb_cPathname, "each_entry", path_each_entry, 0);
1596     rb_define_method(rb_cPathname, "unlink", path_unlink, 0);
1597     rb_define_method(rb_cPathname, "delete", path_unlink, 0);
1598     rb_undef_method(rb_cPathname, "=~");
1599     rb_define_global_function("Pathname", path_f_pathname, 1);
1600 }
1601 
1602 void
InitVM_pathname(void)1603 InitVM_pathname(void)
1604 {
1605 #undef rb_intern
1606     id_at_path = rb_intern("@path");
1607     id_to_path = rb_intern("to_path");
1608     id_ENOTDIR = rb_intern("ENOTDIR");
1609     id_atime = rb_intern("atime");
1610     id_basename = rb_intern("basename");
1611     id_base = rb_intern("base");
1612     id_binread = rb_intern("binread");
1613     id_binwrite = rb_intern("binwrite");
1614     id_birthtime = rb_intern("birthtime");
1615     id_blockdev_p = rb_intern("blockdev?");
1616     id_chardev_p = rb_intern("chardev?");
1617     id_chmod = rb_intern("chmod");
1618     id_chown = rb_intern("chown");
1619     id_ctime = rb_intern("ctime");
1620     id_directory_p = rb_intern("directory?");
1621     id_dirname = rb_intern("dirname");
1622     id_empty_p = rb_intern("empty?");
1623     id_entries = rb_intern("entries");
1624     id_executable_p = rb_intern("executable?");
1625     id_executable_real_p = rb_intern("executable_real?");
1626     id_exist_p = rb_intern("exist?");
1627     id_expand_path = rb_intern("expand_path");
1628     id_extname = rb_intern("extname");
1629     id_file_p = rb_intern("file?");
1630     id_fnmatch = rb_intern("fnmatch");
1631     id_foreach = rb_intern("foreach");
1632     id_ftype = rb_intern("ftype");
1633     id_getwd = rb_intern("getwd");
1634     id_glob = rb_intern("glob");
1635     id_grpowned_p = rb_intern("grpowned?");
1636     id_lchmod = rb_intern("lchmod");
1637     id_lchown = rb_intern("lchown");
1638     id_link = rb_intern("link");
1639     id_lstat = rb_intern("lstat");
1640     id_mkdir = rb_intern("mkdir");
1641     id_mtime = rb_intern("mtime");
1642     id_open = rb_intern("open");
1643     id_owned_p = rb_intern("owned?");
1644     id_pipe_p = rb_intern("pipe?");
1645     id_read = rb_intern("read");
1646     id_readable_p = rb_intern("readable?");
1647     id_readable_real_p = rb_intern("readable_real?");
1648     id_readlines = rb_intern("readlines");
1649     id_readlink = rb_intern("readlink");
1650     id_realdirpath = rb_intern("realdirpath");
1651     id_realpath = rb_intern("realpath");
1652     id_rename = rb_intern("rename");
1653     id_rmdir = rb_intern("rmdir");
1654     id_setgid_p = rb_intern("setgid?");
1655     id_setuid_p = rb_intern("setuid?");
1656     id_size = rb_intern("size");
1657     id_size_p = rb_intern("size?");
1658     id_socket_p = rb_intern("socket?");
1659     id_split = rb_intern("split");
1660     id_stat = rb_intern("stat");
1661     id_sticky_p = rb_intern("sticky?");
1662     id_sub = rb_intern("sub");
1663     id_symlink = rb_intern("symlink");
1664     id_symlink_p = rb_intern("symlink?");
1665     id_sysopen = rb_intern("sysopen");
1666     id_truncate = rb_intern("truncate");
1667     id_unlink = rb_intern("unlink");
1668     id_utime = rb_intern("utime");
1669     id_world_readable_p = rb_intern("world_readable?");
1670     id_world_writable_p = rb_intern("world_writable?");
1671     id_writable_p = rb_intern("writable?");
1672     id_writable_real_p = rb_intern("writable_real?");
1673     id_write = rb_intern("write");
1674     id_zero_p = rb_intern("zero?");
1675 }
1676