diff options
Diffstat (limited to 'pathname.c')
| -rw-r--r-- | pathname.c | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/pathname.c b/pathname.c new file mode 100644 index 0000000000..71c78d89e7 --- /dev/null +++ b/pathname.c @@ -0,0 +1,117 @@ +#include "ruby.h" + +static VALUE rb_cPathname; +static ID id_at_path; +static ID id_sub; + +static VALUE +get_strpath(VALUE obj) +{ + VALUE strpath; + strpath = rb_ivar_get(obj, id_at_path); + if (!RB_TYPE_P(strpath, T_STRING)) + rb_raise(rb_eTypeError, "unexpected @path"); + return strpath; +} + +/* + * Provides a case-sensitive comparison operator for pathnames. + * + * Pathname.new('/usr') <=> Pathname.new('/usr/bin') + * #=> -1 + * Pathname.new('/usr/bin') <=> Pathname.new('/usr/bin') + * #=> 0 + * Pathname.new('/usr/bin') <=> Pathname.new('/USR/BIN') + * #=> 1 + * + * It will return +-1+, +0+ or +1+ depending on the value of the left argument + * relative to the right argument. Or it will return +nil+ if the arguments + * are not comparable. + */ +static VALUE +path_cmp(VALUE self, VALUE other) +{ + VALUE s1, s2; + char *p1, *p2; + char *e1, *e2; + if (!rb_obj_is_kind_of(other, rb_cPathname)) + return Qnil; + s1 = get_strpath(self); + s2 = get_strpath(other); + p1 = RSTRING_PTR(s1); + p2 = RSTRING_PTR(s2); + e1 = p1 + RSTRING_LEN(s1); + e2 = p2 + RSTRING_LEN(s2); + while (p1 < e1 && p2 < e2) { + int c1, c2; + c1 = (unsigned char)*p1++; + c2 = (unsigned char)*p2++; + if (c1 == '/') c1 = '\0'; + if (c2 == '/') c2 = '\0'; + if (c1 != c2) { + if (c1 < c2) + return INT2FIX(-1); + else + return INT2FIX(1); + } + } + if (p1 < e1) + return INT2FIX(1); + if (p2 < e2) + return INT2FIX(-1); + return INT2FIX(0); +} + +/* + * Return a pathname which is substituted by String#sub. + * + * path1 = Pathname.new('/usr/bin/perl') + * path1.sub('perl', 'ruby') + * #=> #<Pathname:/usr/bin/ruby> + */ +static VALUE +path_sub(int argc, VALUE *argv, VALUE self) +{ + VALUE str = get_strpath(self); + + if (rb_block_given_p()) { + str = rb_block_call(str, id_sub, argc, argv, 0, 0); + } + else { + str = rb_funcallv(str, id_sub, argc, argv); + } + return rb_class_new_instance(1, &str, rb_obj_class(self)); +} + +#include "pathname_builtin.rbinc" + +static void init_ids(void); + +void +Init_pathname(void) +{ +#ifdef HAVE_RB_EXT_RACTOR_SAFE + rb_ext_ractor_safe(true); +#endif + + init_ids(); + InitVM(pathname); +} + +void +InitVM_pathname(void) +{ + rb_cPathname = rb_define_class("Pathname", rb_cObject); + rb_define_method(rb_cPathname, "<=>", path_cmp, 1); + rb_define_method(rb_cPathname, "sub", path_sub, -1); + + rb_provide("pathname.so"); +} + +void +init_ids(void) +{ +#undef rb_intern + id_at_path = rb_intern("@path"); + id_sub = rb_intern("sub"); +} |
