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