Ruby 3.5.0dev (2025-10-11 revision 2de13f4d094a92099de92b91cde8d5a7da8c38cc)
pathname.c (2de13f4d094a92099de92b91cde8d5a7da8c38cc)
1#include "ruby.h"
2
3static VALUE rb_cPathname;
4static ID id_at_path;
5static ID id_sub;
6
7static VALUE
8get_strpath(VALUE obj)
9{
10 VALUE strpath;
11 strpath = rb_ivar_get(obj, id_at_path);
12 if (!RB_TYPE_P(strpath, T_STRING))
13 rb_raise(rb_eTypeError, "unexpected @path");
14 return strpath;
15}
16
17/*
18 * Provides a case-sensitive comparison operator for pathnames.
19 *
20 * Pathname.new('/usr') <=> Pathname.new('/usr/bin')
21 * #=> -1
22 * Pathname.new('/usr/bin') <=> Pathname.new('/usr/bin')
23 * #=> 0
24 * Pathname.new('/usr/bin') <=> Pathname.new('/USR/BIN')
25 * #=> 1
26 *
27 * It will return +-1+, +0+ or +1+ depending on the value of the left argument
28 * relative to the right argument. Or it will return +nil+ if the arguments
29 * are not comparable.
30 */
31static VALUE
32path_cmp(VALUE self, VALUE other)
33{
34 VALUE s1, s2;
35 char *p1, *p2;
36 char *e1, *e2;
37 if (!rb_obj_is_kind_of(other, rb_cPathname))
38 return Qnil;
39 s1 = get_strpath(self);
40 s2 = get_strpath(other);
41 p1 = RSTRING_PTR(s1);
42 p2 = RSTRING_PTR(s2);
43 e1 = p1 + RSTRING_LEN(s1);
44 e2 = p2 + RSTRING_LEN(s2);
45 while (p1 < e1 && p2 < e2) {
46 int c1, c2;
47 c1 = (unsigned char)*p1++;
48 c2 = (unsigned char)*p2++;
49 if (c1 == '/') c1 = '\0';
50 if (c2 == '/') c2 = '\0';
51 if (c1 != c2) {
52 if (c1 < c2)
53 return INT2FIX(-1);
54 else
55 return INT2FIX(1);
56 }
57 }
58 if (p1 < e1)
59 return INT2FIX(1);
60 if (p2 < e2)
61 return INT2FIX(-1);
62 return INT2FIX(0);
63}
64
65/*
66 * Return a pathname which is substituted by String#sub.
67 *
68 * path1 = Pathname.new('/usr/bin/perl')
69 * path1.sub('perl', 'ruby')
70 * #=> #<Pathname:/usr/bin/ruby>
71 */
72static VALUE
73path_sub(int argc, VALUE *argv, VALUE self)
74{
75 VALUE str = get_strpath(self);
76
77 if (rb_block_given_p()) {
78 str = rb_block_call(str, id_sub, argc, argv, 0, 0);
79 }
80 else {
81 str = rb_funcallv(str, id_sub, argc, argv);
82 }
83 return rb_class_new_instance(1, &str, rb_obj_class(self));
84}
85
86#include "pathname_builtin.rbinc"
87
88static void init_ids(void);
89
90void
91Init_pathname(void)
92{
93#ifdef HAVE_RB_EXT_RACTOR_SAFE
95#endif
96
97 init_ids();
98 InitVM(pathname);
99}
100
101void
102InitVM_pathname(void)
103{
104 rb_cPathname = rb_define_class("Pathname", rb_cObject);
105 rb_define_method(rb_cPathname, "<=>", path_cmp, 1);
106 rb_define_method(rb_cPathname, "sub", path_sub, -1);
107
108 rb_provide("pathname.so");
109}
110
111void
112init_ids(void)
113{
114#undef rb_intern
115 id_at_path = rb_intern("@path");
116 id_sub = rb_intern("sub");
117}
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition class.c:1484
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:1037
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define Qnil
Old name of RUBY_Qnil.
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1430
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:2205
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:265
VALUE rb_obj_is_kind_of(VALUE obj, VALUE klass)
Queries if the given object is an instance (of possibly descendants) of the given class.
Definition object.c:910
void rb_provide(const char *feature)
Declares that the given feature is already provided by someone else.
Definition load.c:705
void rb_ext_ractor_safe(bool flag)
Asserts that the extension library that calls this function is aware of Ractor.
Definition load.c:1275
VALUE rb_ivar_get(VALUE obj, ID name)
Identical to rb_iv_get(), except it accepts the name as an ID instead of a C string.
Definition variable.c:1460
VALUE rb_block_call(VALUE q, ID w, int e, const VALUE *r, type *t, VALUE y)
Call a method with a block.
#define InitVM(ext)
This macro is for internal use.
Definition ruby.h:231
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376