Ruby 3.0.5p211 (2022-11-24 revision ba5cf0f7c52d4d35cc6a173c89eda98ceffa2dcf)
pathname.c
Go to the documentation of this file.
1#include "ruby.h"
2#include "ruby/encoding.h"
3
4static VALUE rb_cPathname;
5static ID id_ENOTDIR;
6static ID id_at_path;
7static ID id_atime;
8static ID id_base;
9static ID id_basename;
10static ID id_binread;
11static ID id_binwrite;
12static ID id_birthtime;
13static ID id_blockdev_p;
14static ID id_chardev_p;
15static ID id_chmod;
16static ID id_chown;
17static ID id_ctime;
18static ID id_directory_p;
19static ID id_dirname;
20static ID id_empty_p;
21static ID id_entries;
22static ID id_executable_p;
23static ID id_executable_real_p;
24static ID id_exist_p;
25static ID id_expand_path;
26static ID id_extname;
27static ID id_file_p;
28static ID id_fnmatch;
29static ID id_foreach;
30static ID id_ftype;
31static ID id_getwd;
32static ID id_glob;
33static ID id_grpowned_p;
34static ID id_lchmod;
35static ID id_lchown;
36static ID id_link;
37static ID id_lstat;
38static ID id_mkdir;
39static ID id_mtime;
40static ID id_open;
41static ID id_owned_p;
42static ID id_pipe_p;
43static ID id_read;
44static ID id_readable_p;
45static ID id_readable_real_p;
46static ID id_readlines;
47static ID id_readlink;
48static ID id_realdirpath;
49static ID id_realpath;
50static ID id_rename;
51static ID id_rmdir;
52static ID id_setgid_p;
53static ID id_setuid_p;
54static ID id_size;
55static ID id_size_p;
56static ID id_socket_p;
57static ID id_split;
58static ID id_stat;
59static ID id_sticky_p;
60static ID id_sub;
61static ID id_symlink;
62static ID id_symlink_p;
63static ID id_sysopen;
64static ID id_to_path;
65static ID id_truncate;
66static ID id_unlink;
67static ID id_utime;
68static ID id_world_readable_p;
69static ID id_world_writable_p;
70static ID id_writable_p;
71static ID id_writable_real_p;
72static ID id_write;
73static ID id_zero_p;
74
75static VALUE
76get_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
85static void
86set_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 */
95static VALUE
96path_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;
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 return self;
114}
115
116/*
117 * call-seq:
118 * pathname.freeze -> obj
119 *
120 * Freezes this Pathname.
121 *
122 * See Object.freeze.
123 */
124static VALUE
125path_freeze(VALUE self)
126{
127 rb_call_super(0, 0);
128 rb_str_freeze(get_strpath(self));
129 return self;
130}
131
132/*
133 * call-seq:
134 * pathname.taint -> obj
135 *
136 * Returns pathname. This method is deprecated and will be removed in Ruby 3.2.
137 */
138static VALUE
139path_taint(VALUE self)
140{
141 rb_warn("Pathname#taint is deprecated and will be removed in Ruby 3.2.");
142 return self;
143}
144
145/*
146 * call-seq:
147 * pathname.untaint -> obj
148 *
149 * Returns pathname. This method is deprecated and will be removed in Ruby 3.2.
150 */
151static VALUE
152path_untaint(VALUE self)
153{
154 rb_warn("Pathname#untaint is deprecated and will be removed in Ruby 3.2.");
155 return self;
156}
157
158/*
159 * Compare this pathname with +other+. The comparison is string-based.
160 * Be aware that two different paths (<tt>foo.txt</tt> and <tt>./foo.txt</tt>)
161 * can refer to the same file.
162 */
163static VALUE
164path_eq(VALUE self, VALUE other)
165{
166 if (!rb_obj_is_kind_of(other, rb_cPathname))
167 return Qfalse;
168 return rb_str_equal(get_strpath(self), get_strpath(other));
169}
170
171/*
172 * Provides a case-sensitive comparison operator for pathnames.
173 *
174 * Pathname.new('/usr') <=> Pathname.new('/usr/bin')
175 * #=> -1
176 * Pathname.new('/usr/bin') <=> Pathname.new('/usr/bin')
177 * #=> 0
178 * Pathname.new('/usr/bin') <=> Pathname.new('/USR/BIN')
179 * #=> 1
180 *
181 * It will return +-1+, +0+ or +1+ depending on the value of the left argument
182 * relative to the right argument. Or it will return +nil+ if the arguments
183 * are not comparable.
184 */
185static VALUE
186path_cmp(VALUE self, VALUE other)
187{
188 VALUE s1, s2;
189 char *p1, *p2;
190 char *e1, *e2;
191 if (!rb_obj_is_kind_of(other, rb_cPathname))
192 return Qnil;
193 s1 = get_strpath(self);
194 s2 = get_strpath(other);
195 p1 = RSTRING_PTR(s1);
196 p2 = RSTRING_PTR(s2);
197 e1 = p1 + RSTRING_LEN(s1);
198 e2 = p2 + RSTRING_LEN(s2);
199 while (p1 < e1 && p2 < e2) {
200 int c1, c2;
201 c1 = (unsigned char)*p1++;
202 c2 = (unsigned char)*p2++;
203 if (c1 == '/') c1 = '\0';
204 if (c2 == '/') c2 = '\0';
205 if (c1 != c2) {
206 if (c1 < c2)
207 return INT2FIX(-1);
208 else
209 return INT2FIX(1);
210 }
211 }
212 if (p1 < e1)
213 return INT2FIX(1);
214 if (p2 < e2)
215 return INT2FIX(-1);
216 return INT2FIX(0);
217}
218
219#ifndef ST2FIX
220#define ST2FIX(h) LONG2FIX((long)(h))
221#endif
222
223/* :nodoc: */
224static VALUE
225path_hash(VALUE self)
226{
227 return ST2FIX(rb_str_hash(get_strpath(self)));
228}
229
230/*
231 * call-seq:
232 * pathname.to_s -> string
233 * pathname.to_path -> string
234 *
235 * Return the path as a String.
236 *
237 * to_path is implemented so Pathname objects are usable with File.open, etc.
238 */
239static VALUE
240path_to_s(VALUE self)
241{
242 return rb_obj_dup(get_strpath(self));
243}
244
245/* :nodoc: */
246static VALUE
247path_inspect(VALUE self)
248{
249 const char *c = rb_obj_classname(self);
250 VALUE str = get_strpath(self);
251 return rb_sprintf("#<%s:%"PRIsVALUE">", c, str);
252}
253
254/*
255 * Return a pathname which is substituted by String#sub.
256 *
257 * path1 = Pathname.new('/usr/bin/perl')
258 * path1.sub('perl', 'ruby')
259 * #=> #<Pathname:/usr/bin/ruby>
260 */
261static VALUE
262path_sub(int argc, VALUE *argv, VALUE self)
263{
264 VALUE str = get_strpath(self);
265
266 if (rb_block_given_p()) {
267 str = rb_block_call(str, id_sub, argc, argv, 0, 0);
268 }
269 else {
270 str = rb_funcallv(str, id_sub, argc, argv);
271 }
272 return rb_class_new_instance(1, &str, rb_obj_class(self));
273}
274
275/*
276 * Return a pathname with +repl+ added as a suffix to the basename.
277 *
278 * If self has no extension part, +repl+ is appended.
279 *
280 * Pathname.new('/usr/bin/shutdown').sub_ext('.rb')
281 * #=> #<Pathname:/usr/bin/shutdown.rb>
282 */
283static VALUE
284path_sub_ext(VALUE self, VALUE repl)
285{
286 VALUE str = get_strpath(self);
287 VALUE str2;
288 long extlen;
289 const char *ext;
290 const char *p;
291
292 StringValue(repl);
293 p = RSTRING_PTR(str);
294 extlen = RSTRING_LEN(str);
295 ext = ruby_enc_find_extname(p, &extlen, rb_enc_get(str));
296 if (ext == NULL) {
297 ext = p + RSTRING_LEN(str);
298 }
299 else if (extlen <= 1) {
300 ext += extlen;
301 }
302 str2 = rb_str_subseq(str, 0, ext-p);
303 rb_str_append(str2, repl);
304 return rb_class_new_instance(1, &str2, rb_obj_class(self));
305}
306
307/* Facade for File */
308
309/*
310 * Returns the real (absolute) pathname for +self+ in the actual
311 * filesystem.
312 *
313 * Does not contain symlinks or useless dots, +..+ and +.+.
314 *
315 * All components of the pathname must exist when this method is
316 * called.
317 *
318 */
319static VALUE
320path_realpath(int argc, VALUE *argv, VALUE self)
321{
322 VALUE basedir, str;
323 rb_scan_args(argc, argv, "01", &basedir);
324 str = rb_funcall(rb_cFile, id_realpath, 2, get_strpath(self), basedir);
325 return rb_class_new_instance(1, &str, rb_obj_class(self));
326}
327
328/*
329 * Returns the real (absolute) pathname of +self+ in the actual filesystem.
330 *
331 * Does not contain symlinks or useless dots, +..+ and +.+.
332 *
333 * The last component of the real pathname can be nonexistent.
334 */
335static VALUE
336path_realdirpath(int argc, VALUE *argv, VALUE self)
337{
338 VALUE basedir, str;
339 rb_scan_args(argc, argv, "01", &basedir);
340 str = rb_funcall(rb_cFile, id_realdirpath, 2, get_strpath(self), basedir);
341 return rb_class_new_instance(1, &str, rb_obj_class(self));
342}
343
344/*
345 * call-seq:
346 * pathname.each_line {|line| ... }
347 * pathname.each_line(sep=$/ [, open_args]) {|line| block } -> nil
348 * pathname.each_line(limit [, open_args]) {|line| block } -> nil
349 * pathname.each_line(sep, limit [, open_args]) {|line| block } -> nil
350 * pathname.each_line(...) -> an_enumerator
351 *
352 * Iterates over each line in the file and yields a String object for each.
353 */
354static VALUE
355path_each_line(int argc, VALUE *argv, VALUE self)
356{
357 VALUE args[4];
358 int n;
359
360 args[0] = get_strpath(self);
361 n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
362 if (rb_block_given_p()) {
363 return rb_block_call_kw(rb_cFile, id_foreach, 1+n, args, 0, 0, RB_PASS_CALLED_KEYWORDS);
364 }
365 else {
366 return rb_funcallv_kw(rb_cFile, id_foreach, 1+n, args, RB_PASS_CALLED_KEYWORDS);
367 }
368}
369
370/*
371 * call-seq:
372 * pathname.read([length [, offset]]) -> string
373 * pathname.read([length [, offset]], open_args) -> string
374 *
375 * Returns all data from the file, or the first +N+ bytes if specified.
376 *
377 * See File.read.
378 *
379 */
380static VALUE
381path_read(int argc, VALUE *argv, VALUE self)
382{
383 VALUE args[4];
384 int n;
385
386 args[0] = get_strpath(self);
387 n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
388 return rb_funcallv_kw(rb_cFile, id_read, 1+n, args, RB_PASS_CALLED_KEYWORDS);
389}
390
391/*
392 * call-seq:
393 * pathname.binread([length [, offset]]) -> string
394 *
395 * Returns all the bytes from the file, or the first +N+ if specified.
396 *
397 * See File.binread.
398 *
399 */
400static VALUE
401path_binread(int argc, VALUE *argv, VALUE self)
402{
403 VALUE args[3];
404 int n;
405
406 args[0] = get_strpath(self);
407 n = rb_scan_args(argc, argv, "02", &args[1], &args[2]);
408 return rb_funcallv(rb_cFile, id_binread, 1+n, args);
409}
410
411/*
412 * call-seq:
413 * pathname.write(string, [offset] ) => fixnum
414 * pathname.write(string, [offset], open_args ) => fixnum
415 *
416 * Writes +contents+ to the file.
417 *
418 * See File.write.
419 *
420 */
421static VALUE
422path_write(int argc, VALUE *argv, VALUE self)
423{
424 VALUE args[4];
425 int n;
426
427 args[0] = get_strpath(self);
428 n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
429 return rb_funcallv_kw(rb_cFile, id_write, 1+n, args, RB_PASS_CALLED_KEYWORDS);
430}
431
432/*
433 * call-seq:
434 * pathname.binwrite(string, [offset] ) => fixnum
435 * pathname.binwrite(string, [offset], open_args ) => fixnum
436 *
437 * Writes +contents+ to the file, opening it in binary mode.
438 *
439 * See File.binwrite.
440 *
441 */
442static VALUE
443path_binwrite(int argc, VALUE *argv, VALUE self)
444{
445 VALUE args[4];
446 int n;
447
448 args[0] = get_strpath(self);
449 n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
450 return rb_funcallv_kw(rb_cFile, id_binwrite, 1+n, args, RB_PASS_CALLED_KEYWORDS);
451}
452
453/*
454 * call-seq:
455 * pathname.readlines(sep=$/ [, open_args]) -> array
456 * pathname.readlines(limit [, open_args]) -> array
457 * pathname.readlines(sep, limit [, open_args]) -> array
458 *
459 * Returns all the lines from the file.
460 *
461 * See File.readlines.
462 *
463 */
464static VALUE
465path_readlines(int argc, VALUE *argv, VALUE self)
466{
467 VALUE args[4];
468 int n;
469
470 args[0] = get_strpath(self);
471 n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
472 return rb_funcallv_kw(rb_cFile, id_readlines, 1+n, args, RB_PASS_CALLED_KEYWORDS);
473}
474
475/*
476 * call-seq:
477 * pathname.sysopen([mode, [perm]]) -> fixnum
478 *
479 * See IO.sysopen.
480 *
481 */
482static VALUE
483path_sysopen(int argc, VALUE *argv, VALUE self)
484{
485 VALUE args[3];
486 int n;
487
488 args[0] = get_strpath(self);
489 n = rb_scan_args(argc, argv, "02", &args[1], &args[2]);
490 return rb_funcallv(rb_cIO, id_sysopen, 1+n, args);
491}
492
493/*
494 * call-seq:
495 * pathname.atime -> time
496 *
497 * Returns the last access time for the file.
498 *
499 * See File.atime.
500 */
501static VALUE
502path_atime(VALUE self)
503{
504 return rb_funcall(rb_cFile, id_atime, 1, get_strpath(self));
505}
506
507#if defined(HAVE_RB_FILE_S_BIRTHTIME)
508/*
509 * call-seq:
510 * pathname.birthtime -> time
511 *
512 * Returns the birth time for the file.
513 * If the platform doesn't have birthtime, raises NotImplementedError.
514 *
515 * See File.birthtime.
516 */
517static VALUE
519{
520 return rb_funcall(rb_cFile, id_birthtime, 1, get_strpath(self));
521}
522#else
523/* check at compilation time for `respond_to?` */
524# define path_birthtime rb_f_notimplement
525#endif
526
527/*
528 * call-seq:
529 * pathname.ctime -> time
530 *
531 * Returns the last change time, using directory information, not the file itself.
532 *
533 * See File.ctime.
534 */
535static VALUE
536path_ctime(VALUE self)
537{
538 return rb_funcall(rb_cFile, id_ctime, 1, get_strpath(self));
539}
540
541/*
542 * call-seq:
543 * pathname.mtime -> time
544 *
545 * Returns the last modified time of the file.
546 *
547 * See File.mtime.
548 */
549static VALUE
550path_mtime(VALUE self)
551{
552 return rb_funcall(rb_cFile, id_mtime, 1, get_strpath(self));
553}
554
555/*
556 * call-seq:
557 * pathname.chmod(mode_int) -> integer
558 *
559 * Changes file permissions.
560 *
561 * See File.chmod.
562 */
563static VALUE
564path_chmod(VALUE self, VALUE mode)
565{
566 return rb_funcall(rb_cFile, id_chmod, 2, mode, get_strpath(self));
567}
568
569/*
570 * call-seq:
571 * pathname.lchmod(mode_int) -> integer
572 *
573 * Same as Pathname.chmod, but does not follow symbolic links.
574 *
575 * See File.lchmod.
576 */
577static VALUE
578path_lchmod(VALUE self, VALUE mode)
579{
580 return rb_funcall(rb_cFile, id_lchmod, 2, mode, get_strpath(self));
581}
582
583/*
584 * call-seq:
585 * pathname.chown(owner_int, group_int) -> integer
586 *
587 * Change owner and group of the file.
588 *
589 * See File.chown.
590 */
591static VALUE
592path_chown(VALUE self, VALUE owner, VALUE group)
593{
594 return rb_funcall(rb_cFile, id_chown, 3, owner, group, get_strpath(self));
595}
596
597/*
598 * call-seq:
599 * pathname.lchown(owner_int, group_int) -> integer
600 *
601 * Same as Pathname.chown, but does not follow symbolic links.
602 *
603 * See File.lchown.
604 */
605static VALUE
606path_lchown(VALUE self, VALUE owner, VALUE group)
607{
608 return rb_funcall(rb_cFile, id_lchown, 3, owner, group, get_strpath(self));
609}
610
611/*
612 * call-seq:
613 * pathname.fnmatch(pattern, [flags]) -> true or false
614 * pathname.fnmatch?(pattern, [flags]) -> true or false
615 *
616 * Return +true+ if the receiver matches the given pattern.
617 *
618 * See File.fnmatch.
619 */
620static VALUE
621path_fnmatch(int argc, VALUE *argv, VALUE self)
622{
623 VALUE str = get_strpath(self);
624 VALUE pattern, flags;
625 if (rb_scan_args(argc, argv, "11", &pattern, &flags) == 1)
626 return rb_funcall(rb_cFile, id_fnmatch, 2, pattern, str);
627 else
628 return rb_funcall(rb_cFile, id_fnmatch, 3, pattern, str, flags);
629}
630
631/*
632 * call-seq:
633 * pathname.ftype -> string
634 *
635 * Returns "type" of file ("file", "directory", etc).
636 *
637 * See File.ftype.
638 */
639static VALUE
640path_ftype(VALUE self)
641{
642 return rb_funcall(rb_cFile, id_ftype, 1, get_strpath(self));
643}
644
645/*
646 * call-seq:
647 * pathname.make_link(old)
648 *
649 * Creates a hard link at _pathname_.
650 *
651 * See File.link.
652 */
653static VALUE
654path_make_link(VALUE self, VALUE old)
655{
656 return rb_funcall(rb_cFile, id_link, 2, old, get_strpath(self));
657}
658
659/*
660 * call-seq:
661 * pathname.open()
662 * pathname.open(mode="r" [, opt]) -> file
663 * pathname.open([mode [, perm]] [, opt]) -> file
664 * pathname.open(mode="r" [, opt]) {|file| block } -> obj
665 * pathname.open([mode [, perm]] [, opt]) {|file| block } -> obj
666 *
667 * Opens the file for reading or writing.
668 *
669 * See File.open.
670 */
671static VALUE
672path_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_kw(rb_cFile, id_open, 1+n, args, 0, 0, RB_PASS_CALLED_KEYWORDS);
681 }
682 else {
683 return rb_funcallv_kw(rb_cFile, id_open, 1+n, args, RB_PASS_CALLED_KEYWORDS);
684 }
685}
686
687/*
688 * Read symbolic link.
689 *
690 * See File.readlink.
691 */
692static VALUE
693path_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 */
705static VALUE
706path_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 */
716static VALUE
717path_stat(VALUE self)
718{
719 return rb_funcall(rb_cFile, id_stat, 1, get_strpath(self));
720}
721
722/*
723 * See File.lstat.
724 */
725static VALUE
726path_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 */
739static VALUE
740path_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 */
750static VALUE
751path_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 */
761static VALUE
762path_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 */
772static VALUE
773path_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 */
789static VALUE
790path_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 */
802static VALUE
803path_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 */
814static VALUE
815path_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 */
831static VALUE
832path_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 */
848static VALUE
849path_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 */
857static VALUE
858path_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 */
866static VALUE
867path_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 */
875static VALUE
876path_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 */
884static VALUE
885path_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 */
893static VALUE
894path_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 */
902static VALUE
903path_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 */
911static VALUE
912path_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 */
920static VALUE
921path_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 */
929static VALUE
930path_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 */
938static VALUE
939path_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 */
947static VALUE
948path_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 */
956static VALUE
957path_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 */
965static VALUE
966path_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 */
974static VALUE
975path_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 */
983static VALUE
984path_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 */
992static VALUE
993path_size(VALUE self)
994{
995 return rb_funcall(rb_mFileTest, id_size, 1, get_strpath(self));
996}
997
998/*
999 * See FileTest.size?.
1000 */
1001static VALUE
1002path_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 */
1010static VALUE
1011path_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 */
1019static VALUE
1020path_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 */
1028static VALUE
1029path_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 */
1037static VALUE
1038path_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 */
1046static VALUE
1047path_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 */
1055static VALUE
1056path_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 */
1066static VALUE
1067path_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
1077static VALUE
1078s_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 */
1091static VALUE
1092path_s_glob(int argc, VALUE *argv, VALUE klass)
1093{
1094 VALUE args[3];
1095 int n;
1096
1097 n = rb_scan_args(argc, argv, "12", &args[0], &args[1], &args[2]);
1098 if (rb_block_given_p()) {
1099 return rb_block_call_kw(rb_cDir, id_glob, n, args, s_glob_i, klass, RB_PASS_CALLED_KEYWORDS);
1100 }
1101 else {
1102 VALUE ary;
1103 long i;
1104 ary = rb_funcallv_kw(rb_cDir, id_glob, n, args, RB_PASS_CALLED_KEYWORDS);
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
1115static VALUE
1116glob_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 */
1131static VALUE
1132path_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_kw(rb_cDir, id_glob, n, args, glob_i, self, RB_PASS_KEYWORDS);
1148 }
1149 else {
1150 VALUE ary;
1151 long i;
1152 ary = rb_funcallv_kw(rb_cDir, id_glob, n, args, RB_PASS_KEYWORDS);
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 */
1171static VALUE
1172path_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 */
1205static VALUE
1206path_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 */
1227static VALUE
1228path_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 */
1243static VALUE
1244path_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 */
1254static VALUE
1255path_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
1263static VALUE
1264each_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 */
1273static VALUE
1274path_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
1282static VALUE
1283unlink_body(VALUE str)
1284{
1285 return rb_funcall(rb_cDir, id_unlink, 1, str);
1286}
1287
1288static VALUE
1289unlink_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 */
1298static VALUE
1299path_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 */
1322static VALUE
1323path_f_pathname(VALUE self, VALUE str)
1324{
1325 if (CLASS_OF(str) == rb_cPathname)
1326 return str;
1327 return rb_class_new_instance(1, &str, rb_cPathname);
1328}
1329
1330/*
1331 *
1332 * Pathname represents the name of a file or directory on the filesystem,
1333 * but not the file itself.
1334 *
1335 * The pathname depends on the Operating System: Unix, Windows, etc.
1336 * This library works with pathnames of local OS, however non-Unix pathnames
1337 * are supported experimentally.
1338 *
1339 * A Pathname can be relative or absolute. It's not until you try to
1340 * reference the file that it even matters whether the file exists or not.
1341 *
1342 * Pathname is immutable. It has no method for destructive update.
1343 *
1344 * The goal of this class is to manipulate file path information in a neater
1345 * way than standard Ruby provides. The examples below demonstrate the
1346 * difference.
1347 *
1348 * *All* functionality from File, FileTest, and some from Dir and FileUtils is
1349 * included, in an unsurprising way. It is essentially a facade for all of
1350 * these, and more.
1351 *
1352 * == Examples
1353 *
1354 * === Example 1: Using Pathname
1355 *
1356 * require 'pathname'
1357 * pn = Pathname.new("/usr/bin/ruby")
1358 * size = pn.size # 27662
1359 * isdir = pn.directory? # false
1360 * dir = pn.dirname # Pathname:/usr/bin
1361 * base = pn.basename # Pathname:ruby
1362 * dir, base = pn.split # [Pathname:/usr/bin, Pathname:ruby]
1363 * data = pn.read
1364 * pn.open { |f| _ }
1365 * pn.each_line { |line| _ }
1366 *
1367 * === Example 2: Using standard Ruby
1368 *
1369 * pn = "/usr/bin/ruby"
1370 * size = File.size(pn) # 27662
1371 * isdir = File.directory?(pn) # false
1372 * dir = File.dirname(pn) # "/usr/bin"
1373 * base = File.basename(pn) # "ruby"
1374 * dir, base = File.split(pn) # ["/usr/bin", "ruby"]
1375 * data = File.read(pn)
1376 * File.open(pn) { |f| _ }
1377 * File.foreach(pn) { |line| _ }
1378 *
1379 * === Example 3: Special features
1380 *
1381 * p1 = Pathname.new("/usr/lib") # Pathname:/usr/lib
1382 * p2 = p1 + "ruby/1.8" # Pathname:/usr/lib/ruby/1.8
1383 * p3 = p1.parent # Pathname:/usr
1384 * p4 = p2.relative_path_from(p3) # Pathname:lib/ruby/1.8
1385 * pwd = Pathname.pwd # Pathname:/home/gavin
1386 * pwd.absolute? # true
1387 * p5 = Pathname.new "." # Pathname:.
1388 * p5 = p5 + "music/../articles" # Pathname:music/../articles
1389 * p5.cleanpath # Pathname:articles
1390 * p5.realpath # Pathname:/home/gavin/articles
1391 * p5.children # [Pathname:/home/gavin/articles/linux, ...]
1392 *
1393 * == Breakdown of functionality
1394 *
1395 * === Core methods
1396 *
1397 * These methods are effectively manipulating a String, because that's
1398 * all a path is. None of these access the file system except for
1399 * #mountpoint?, #children, #each_child, #realdirpath and #realpath.
1400 *
1401 * - +
1402 * - #join
1403 * - #parent
1404 * - #root?
1405 * - #absolute?
1406 * - #relative?
1407 * - #relative_path_from
1408 * - #each_filename
1409 * - #cleanpath
1410 * - #realpath
1411 * - #realdirpath
1412 * - #children
1413 * - #each_child
1414 * - #mountpoint?
1415 *
1416 * === File status predicate methods
1417 *
1418 * These methods are a facade for FileTest:
1419 * - #blockdev?
1420 * - #chardev?
1421 * - #directory?
1422 * - #executable?
1423 * - #executable_real?
1424 * - #exist?
1425 * - #file?
1426 * - #grpowned?
1427 * - #owned?
1428 * - #pipe?
1429 * - #readable?
1430 * - #world_readable?
1431 * - #readable_real?
1432 * - #setgid?
1433 * - #setuid?
1434 * - #size
1435 * - #size?
1436 * - #socket?
1437 * - #sticky?
1438 * - #symlink?
1439 * - #writable?
1440 * - #world_writable?
1441 * - #writable_real?
1442 * - #zero?
1443 *
1444 * === File property and manipulation methods
1445 *
1446 * These methods are a facade for File:
1447 * - #atime
1448 * - #birthtime
1449 * - #ctime
1450 * - #mtime
1451 * - #chmod(mode)
1452 * - #lchmod(mode)
1453 * - #chown(owner, group)
1454 * - #lchown(owner, group)
1455 * - #fnmatch(pattern, *args)
1456 * - #fnmatch?(pattern, *args)
1457 * - #ftype
1458 * - #make_link(old)
1459 * - #open(*args, &block)
1460 * - #readlink
1461 * - #rename(to)
1462 * - #stat
1463 * - #lstat
1464 * - #make_symlink(old)
1465 * - #truncate(length)
1466 * - #utime(atime, mtime)
1467 * - #basename(*args)
1468 * - #dirname
1469 * - #extname
1470 * - #expand_path(*args)
1471 * - #split
1472 *
1473 * === Directory methods
1474 *
1475 * These methods are a facade for Dir:
1476 * - Pathname.glob(*args)
1477 * - Pathname.getwd / Pathname.pwd
1478 * - #rmdir
1479 * - #entries
1480 * - #each_entry(&block)
1481 * - #mkdir(*args)
1482 * - #opendir(*args)
1483 *
1484 * === IO
1485 *
1486 * These methods are a facade for IO:
1487 * - #each_line(*args, &block)
1488 * - #read(*args)
1489 * - #binread(*args)
1490 * - #readlines(*args)
1491 * - #sysopen(*args)
1492 * - #write(*args)
1493 * - #binwrite(*args)
1494 *
1495 * === Utilities
1496 *
1497 * These methods are a mixture of Find, FileUtils, and others:
1498 * - #find(&block)
1499 * - #mkpath
1500 * - #rmtree
1501 * - #unlink / #delete
1502 *
1503 *
1504 * == Method documentation
1505 *
1506 * As the above section shows, most of the methods in Pathname are facades. The
1507 * documentation for these methods generally just says, for instance, "See
1508 * FileTest.writable?", as you should be familiar with the original method
1509 * anyway, and its documentation (e.g. through +ri+) will contain more
1510 * information. In some cases, a brief description will follow.
1511 */
1512void
1514{
1515#ifdef HAVE_RB_EXT_RACTOR_SAFE
1516 rb_ext_ractor_safe(true);
1517#endif
1518
1519 InitVM(pathname);
1520
1521 rb_cPathname = rb_define_class("Pathname", rb_cObject);
1522 rb_define_method(rb_cPathname, "initialize", path_initialize, 1);
1523 rb_define_method(rb_cPathname, "freeze", path_freeze, 0);
1524 rb_define_method(rb_cPathname, "taint", path_taint, 0);
1525 rb_define_method(rb_cPathname, "untaint", path_untaint, 0);
1526 rb_define_method(rb_cPathname, "==", path_eq, 1);
1527 rb_define_method(rb_cPathname, "===", path_eq, 1);
1528 rb_define_method(rb_cPathname, "eql?", path_eq, 1);
1529 rb_define_method(rb_cPathname, "<=>", path_cmp, 1);
1530 rb_define_method(rb_cPathname, "hash", path_hash, 0);
1531 rb_define_method(rb_cPathname, "to_s", path_to_s, 0);
1532 rb_define_method(rb_cPathname, "to_path", path_to_s, 0);
1533 rb_define_method(rb_cPathname, "inspect", path_inspect, 0);
1534 rb_define_method(rb_cPathname, "sub", path_sub, -1);
1535 rb_define_method(rb_cPathname, "sub_ext", path_sub_ext, 1);
1536 rb_define_method(rb_cPathname, "realpath", path_realpath, -1);
1537 rb_define_method(rb_cPathname, "realdirpath", path_realdirpath, -1);
1538 rb_define_method(rb_cPathname, "each_line", path_each_line, -1);
1539 rb_define_method(rb_cPathname, "read", path_read, -1);
1540 rb_define_method(rb_cPathname, "binread", path_binread, -1);
1541 rb_define_method(rb_cPathname, "readlines", path_readlines, -1);
1542 rb_define_method(rb_cPathname, "write", path_write, -1);
1543 rb_define_method(rb_cPathname, "binwrite", path_binwrite, -1);
1544 rb_define_method(rb_cPathname, "sysopen", path_sysopen, -1);
1545 rb_define_method(rb_cPathname, "atime", path_atime, 0);
1546 rb_define_method(rb_cPathname, "birthtime", path_birthtime, 0);
1547 rb_define_method(rb_cPathname, "ctime", path_ctime, 0);
1548 rb_define_method(rb_cPathname, "mtime", path_mtime, 0);
1549 rb_define_method(rb_cPathname, "chmod", path_chmod, 1);
1550 rb_define_method(rb_cPathname, "lchmod", path_lchmod, 1);
1551 rb_define_method(rb_cPathname, "chown", path_chown, 2);
1552 rb_define_method(rb_cPathname, "lchown", path_lchown, 2);
1553 rb_define_method(rb_cPathname, "fnmatch", path_fnmatch, -1);
1554 rb_define_method(rb_cPathname, "fnmatch?", path_fnmatch, -1);
1555 rb_define_method(rb_cPathname, "ftype", path_ftype, 0);
1556 rb_define_method(rb_cPathname, "make_link", path_make_link, 1);
1557 rb_define_method(rb_cPathname, "open", path_open, -1);
1558 rb_define_method(rb_cPathname, "readlink", path_readlink, 0);
1559 rb_define_method(rb_cPathname, "rename", path_rename, 1);
1560 rb_define_method(rb_cPathname, "stat", path_stat, 0);
1561 rb_define_method(rb_cPathname, "lstat", path_lstat, 0);
1562 rb_define_method(rb_cPathname, "make_symlink", path_make_symlink, 1);
1563 rb_define_method(rb_cPathname, "truncate", path_truncate, 1);
1564 rb_define_method(rb_cPathname, "utime", path_utime, 2);
1565 rb_define_method(rb_cPathname, "basename", path_basename, -1);
1566 rb_define_method(rb_cPathname, "dirname", path_dirname, 0);
1567 rb_define_method(rb_cPathname, "extname", path_extname, 0);
1568 rb_define_method(rb_cPathname, "expand_path", path_expand_path, -1);
1569 rb_define_method(rb_cPathname, "split", path_split, 0);
1570 rb_define_method(rb_cPathname, "blockdev?", path_blockdev_p, 0);
1571 rb_define_method(rb_cPathname, "chardev?", path_chardev_p, 0);
1572 rb_define_method(rb_cPathname, "executable?", path_executable_p, 0);
1573 rb_define_method(rb_cPathname, "executable_real?", path_executable_real_p, 0);
1574 rb_define_method(rb_cPathname, "exist?", path_exist_p, 0);
1575 rb_define_method(rb_cPathname, "grpowned?", path_grpowned_p, 0);
1576 rb_define_method(rb_cPathname, "directory?", path_directory_p, 0);
1577 rb_define_method(rb_cPathname, "file?", path_file_p, 0);
1578 rb_define_method(rb_cPathname, "pipe?", path_pipe_p, 0);
1579 rb_define_method(rb_cPathname, "socket?", path_socket_p, 0);
1580 rb_define_method(rb_cPathname, "owned?", path_owned_p, 0);
1581 rb_define_method(rb_cPathname, "readable?", path_readable_p, 0);
1582 rb_define_method(rb_cPathname, "world_readable?", path_world_readable_p, 0);
1583 rb_define_method(rb_cPathname, "readable_real?", path_readable_real_p, 0);
1584 rb_define_method(rb_cPathname, "setuid?", path_setuid_p, 0);
1585 rb_define_method(rb_cPathname, "setgid?", path_setgid_p, 0);
1586 rb_define_method(rb_cPathname, "size", path_size, 0);
1587 rb_define_method(rb_cPathname, "size?", path_size_p, 0);
1588 rb_define_method(rb_cPathname, "sticky?", path_sticky_p, 0);
1589 rb_define_method(rb_cPathname, "symlink?", path_symlink_p, 0);
1590 rb_define_method(rb_cPathname, "writable?", path_writable_p, 0);
1591 rb_define_method(rb_cPathname, "world_writable?", path_world_writable_p, 0);
1592 rb_define_method(rb_cPathname, "writable_real?", path_writable_real_p, 0);
1593 rb_define_method(rb_cPathname, "zero?", path_zero_p, 0);
1594 rb_define_method(rb_cPathname, "empty?", path_empty_p, 0);
1595 rb_define_singleton_method(rb_cPathname, "glob", path_s_glob, -1);
1596 rb_define_singleton_method(rb_cPathname, "getwd", path_s_getwd, 0);
1597 rb_define_singleton_method(rb_cPathname, "pwd", path_s_getwd, 0);
1598 rb_define_method(rb_cPathname, "glob", path_glob, -1);
1599 rb_define_method(rb_cPathname, "entries", path_entries, 0);
1600 rb_define_method(rb_cPathname, "mkdir", path_mkdir, -1);
1601 rb_define_method(rb_cPathname, "rmdir", path_rmdir, 0);
1602 rb_define_method(rb_cPathname, "opendir", path_opendir, 0);
1603 rb_define_method(rb_cPathname, "each_entry", path_each_entry, 0);
1604 rb_define_method(rb_cPathname, "unlink", path_unlink, 0);
1605 rb_define_method(rb_cPathname, "delete", path_unlink, 0);
1606 rb_undef_method(rb_cPathname, "=~");
1607 rb_define_global_function("Pathname", path_f_pathname, 1);
1608}
1609
1610void
1612{
1613#undef rb_intern
1614 id_at_path = rb_intern("@path");
1615 id_to_path = rb_intern("to_path");
1616 id_ENOTDIR = rb_intern("ENOTDIR");
1617 id_atime = rb_intern("atime");
1618 id_basename = rb_intern("basename");
1619 id_base = rb_intern("base");
1620 id_binread = rb_intern("binread");
1621 id_binwrite = rb_intern("binwrite");
1622 id_birthtime = rb_intern("birthtime");
1623 id_blockdev_p = rb_intern("blockdev?");
1624 id_chardev_p = rb_intern("chardev?");
1625 id_chmod = rb_intern("chmod");
1626 id_chown = rb_intern("chown");
1627 id_ctime = rb_intern("ctime");
1628 id_directory_p = rb_intern("directory?");
1629 id_dirname = rb_intern("dirname");
1630 id_empty_p = rb_intern("empty?");
1631 id_entries = rb_intern("entries");
1632 id_executable_p = rb_intern("executable?");
1633 id_executable_real_p = rb_intern("executable_real?");
1634 id_exist_p = rb_intern("exist?");
1635 id_expand_path = rb_intern("expand_path");
1636 id_extname = rb_intern("extname");
1637 id_file_p = rb_intern("file?");
1638 id_fnmatch = rb_intern("fnmatch");
1639 id_foreach = rb_intern("foreach");
1640 id_ftype = rb_intern("ftype");
1641 id_getwd = rb_intern("getwd");
1642 id_glob = rb_intern("glob");
1643 id_grpowned_p = rb_intern("grpowned?");
1644 id_lchmod = rb_intern("lchmod");
1645 id_lchown = rb_intern("lchown");
1646 id_link = rb_intern("link");
1647 id_lstat = rb_intern("lstat");
1648 id_mkdir = rb_intern("mkdir");
1649 id_mtime = rb_intern("mtime");
1650 id_open = rb_intern("open");
1651 id_owned_p = rb_intern("owned?");
1652 id_pipe_p = rb_intern("pipe?");
1653 id_read = rb_intern("read");
1654 id_readable_p = rb_intern("readable?");
1655 id_readable_real_p = rb_intern("readable_real?");
1656 id_readlines = rb_intern("readlines");
1657 id_readlink = rb_intern("readlink");
1658 id_realdirpath = rb_intern("realdirpath");
1659 id_realpath = rb_intern("realpath");
1660 id_rename = rb_intern("rename");
1661 id_rmdir = rb_intern("rmdir");
1662 id_setgid_p = rb_intern("setgid?");
1663 id_setuid_p = rb_intern("setuid?");
1664 id_size = rb_intern("size");
1665 id_size_p = rb_intern("size?");
1666 id_socket_p = rb_intern("socket?");
1667 id_split = rb_intern("split");
1668 id_stat = rb_intern("stat");
1669 id_sticky_p = rb_intern("sticky?");
1670 id_sub = rb_intern("sub");
1671 id_symlink = rb_intern("symlink");
1672 id_symlink_p = rb_intern("symlink?");
1673 id_sysopen = rb_intern("sysopen");
1674 id_truncate = rb_intern("truncate");
1675 id_unlink = rb_intern("unlink");
1676 id_utime = rb_intern("utime");
1677 id_world_readable_p = rb_intern("world_readable?");
1678 id_world_writable_p = rb_intern("world_writable?");
1679 id_writable_p = rb_intern("writable?");
1680 id_writable_real_p = rb_intern("writable_real?");
1681 id_write = rb_intern("write");
1682 id_zero_p = rb_intern("zero?");
1683}
void rb_ary_store(VALUE ary, long idx, VALUE val)
Definition: array.c:1141
VALUE rb_check_array_type(VALUE ary)
Definition: array.c:988
VALUE rb_ary_entry(VALUE ary, long offset)
Definition: array.c:1672
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
Definition: cxxanyargs.hpp:653
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
Definition: cxxanyargs.hpp:668
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
Definition: cxxanyargs.hpp:678
VALUE rb_cDir
Definition: dir.c:450
rb_encoding * rb_enc_get(VALUE obj)
Definition: encoding.c:1070
#define id_size
Definition: enum.c:37
char str[HTML_ESCAPE_MAX_LEN+1]
Definition: escape.c:18
#define RSTRING_LEN(string)
Definition: fbuffer.h:22
#define RSTRING_PTR(string)
Definition: fbuffer.h:19
const char * ruby_enc_find_extname(const char *name, long *len, rb_encoding *enc)
Definition: file.c:4786
VALUE rb_mFileTest
Definition: file.c:175
VALUE rb_cFile
Definition: file.c:174
#define PRIsVALUE
Definition: function.c:10
VALUE rb_cIO
Definition: io.c:183
#define CLASS_OF
Definition: globals.h:153
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition: class.c:748
void rb_undef_method(VALUE klass, const char *name)
Definition: class.c:1777
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:2296
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition: eval.c:935
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2917
VALUE rb_rescue2(VALUE(*b_proc)(VALUE), VALUE data1, VALUE(*r_proc)(VALUE, VALUE), VALUE data2,...)
An equivalent of rescue clause.
Definition: eval.c:991
VALUE rb_mErrno
Definition: error.c:1077
VALUE rb_eTypeError
Definition: error.c:1057
void rb_warn(const char *fmt,...)
Definition: error.c:408
VALUE rb_eArgError
Definition: error.c:1058
VALUE rb_convert_type(VALUE, int, const char *, const char *)
Converts an object into another type.
Definition: object.c:2930
VALUE rb_cObject
Object class.
Definition: object.c:49
VALUE rb_class_new_instance(int, const VALUE *, VALUE)
Allocates and initializes an instance of klass.
Definition: object.c:1953
VALUE rb_obj_class(VALUE)
Definition: object.c:245
VALUE rb_obj_dup(VALUE)
Equivalent to Object#dup in Ruby.
Definition: object.c:467
VALUE rb_obj_is_kind_of(VALUE, VALUE)
Determines if obj is a kind of c.
Definition: object.c:724
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
Definition: hash.c:2901
VALUE rb_hash_new(void)
Definition: hash.c:1538
VALUE rb_funcallv_kw(VALUE, ID, int, const VALUE *, int)
Definition: vm_eval.c:1030
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
Definition: vm_eval.c:1077
VALUE rb_call_super(int, const VALUE *)
Definition: vm_eval.c:298
#define rb_ary_new3
Definition: array.h:73
void rb_ext_ractor_safe(bool flag)
Definition: load.c:1058
VALUE rb_str_freeze(VALUE)
Definition: string.c:2766
VALUE rb_str_equal(VALUE str1, VALUE str2)
Definition: string.c:3423
VALUE rb_str_subseq(VALUE, long, long)
Definition: string.c:2624
VALUE rb_str_append(VALUE, VALUE)
Definition: string.c:3118
st_index_t rb_str_hash(VALUE)
Definition: string.c:3314
VALUE rb_ivar_get(VALUE, ID)
Definition: variable.c:1234
VALUE rb_const_get_at(VALUE, ID)
Definition: variable.c:2630
VALUE rb_ivar_set(VALUE, ID, VALUE)
Definition: variable.c:1493
VALUE rb_check_funcall(VALUE, ID, int, const VALUE *)
Definition: vm_eval.c:619
#define ID2SYM
Definition: symbol.h:44
ID rb_intern(const char *)
Definition: symbol.c:785
#define rb_funcallv(...)
Definition: internal.h:77
const char int mode
Definition: ioapi.h:137
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Definition: iterator.h:31
VALUE rb_block_call_kw(VALUE, ID, int, const VALUE *, rb_block_call_func_t, VALUE, int)
Definition: vm_eval.c:1584
VALUE rb_yield(VALUE)
Definition: vm_eval.c:1341
#define INT2FIX
Definition: long.h:48
VALUE rb_block_call(VALUE q, ID w, int e, const VALUE *r, type *t, VALUE y)
Call a method with a block.
Definition: cxxanyargs.hpp:230
void Init_pathname(void)
Definition: pathname.c:1513
#define path_birthtime
Definition: pathname.c:524
void InitVM_pathname(void)
Definition: pathname.c:1611
#define RARRAY_AREF(a, i)
Definition: psych_emitter.c:7
#define RARRAY_LEN
Definition: rarray.h:52
#define NULL
Definition: regenc.h:69
#define StringValue(v)
Definition: rstring.h:50
const char * rb_obj_classname(VALUE)
Definition: variable.c:308
#define InitVM(ext)
Definition: ruby.h:112
int argc
Definition: ruby.c:240
char ** argv
Definition: ruby.c:241
#define ST2FIX(h)
Definition: ruby_missing.h:21
#define RB_PASS_KEYWORDS
Definition: scan_args.h:47
#define RB_PASS_CALLED_KEYWORDS
Definition: scan_args.h:48
#define Qundef
#define RTEST
#define Qnil
#define Qfalse
VALUE rb_sprintf(const char *,...)
Definition: sprintf.c:1203
unsigned long VALUE
Definition: value.h:38
unsigned long ID
Definition: value.h:39
#define T_STRING
Definition: value_type.h:77
#define T_ARRAY
Definition: value_type.h:55