diff options
Diffstat (limited to 'spec/ruby/optional/capi/ext')
51 files changed, 6551 insertions, 0 deletions
diff --git a/spec/ruby/optional/capi/ext/.gitignore b/spec/ruby/optional/capi/ext/.gitignore new file mode 100644 index 0000000000..577d117bb1 --- /dev/null +++ b/spec/ruby/optional/capi/ext/.gitignore @@ -0,0 +1,9 @@ +# signature of implementation that +# last compiled an extension +*.sig + +# build artifacts +*.o +*.so +*.bundle +*.dll diff --git a/spec/ruby/optional/capi/ext/array_spec.c b/spec/ruby/optional/capi/ext/array_spec.c new file mode 100644 index 0000000000..628c4df9d7 --- /dev/null +++ b/spec/ruby/optional/capi/ext/array_spec.c @@ -0,0 +1,333 @@ +#include "ruby.h" +#include "rubyspec.h" + +#include <stdio.h> + +#ifdef __cplusplus +extern "C" { +#endif + +static VALUE array_spec_rb_Array(VALUE self, VALUE object) { + return rb_Array(object); +} + +static VALUE array_spec_RARRAY_PTR_iterate(VALUE self, VALUE array) { + int i; + VALUE* ptr; + + ptr = RARRAY_PTR(array); + for(i = 0; i < RARRAY_LEN(array); i++) { + rb_yield(ptr[i]); + } + return Qnil; +} + +static VALUE array_spec_RARRAY_PTR_assign(VALUE self, VALUE array, VALUE value) { + int i; + VALUE* ptr; + + ptr = RARRAY_PTR(array); + for(i = 0; i < RARRAY_LEN(array); i++) { + ptr[i] = value; + } + return Qnil; +} + + +static VALUE array_spec_RARRAY_PTR_memcpy(VALUE self, VALUE array1, VALUE array2) { + VALUE *ptr1, *ptr2; + long size; + size = RARRAY_LEN(array1); + ptr1 = RARRAY_PTR(array1); + ptr2 = RARRAY_PTR(array2); + if (ptr1 != NULL && ptr2 != NULL) { + memcpy(ptr2, ptr1, size * sizeof(VALUE)); + } + return Qnil; +} + +static VALUE array_spec_RARRAY_LEN(VALUE self, VALUE array) { + return INT2FIX(RARRAY_LEN(array)); +} + +static VALUE array_spec_RARRAY_AREF(VALUE self, VALUE array, VALUE index) { + return RARRAY_AREF(array, FIX2INT(index)); +} + +static VALUE array_spec_RARRAY_ASET(VALUE self, VALUE array, VALUE index, VALUE value) { + RARRAY_ASET(array, FIX2INT(index), value); + return value; +} + +static VALUE array_spec_rb_ary_aref(int argc, VALUE *argv, VALUE self) { + VALUE ary, args; + rb_scan_args(argc, argv, "1*", &ary, &args); + return rb_ary_aref((int)RARRAY_LEN(args), RARRAY_PTR(args), ary); +} + +static VALUE array_spec_rb_ary_clear(VALUE self, VALUE array) { + return rb_ary_clear(array); +} + +static VALUE array_spec_rb_ary_delete(VALUE self, VALUE array, VALUE item) { + return rb_ary_delete(array, item); +} + +static VALUE array_spec_rb_ary_delete_at(VALUE self, VALUE array, VALUE index) { + return rb_ary_delete_at(array, NUM2LONG(index)); +} + +static VALUE array_spec_rb_ary_dup(VALUE self, VALUE array) { + return rb_ary_dup(array); +} + +static VALUE array_spec_rb_ary_entry(VALUE self, VALUE array, VALUE offset) { + return rb_ary_entry(array, FIX2INT(offset)); +} + +static VALUE array_spec_rb_ary_includes(VALUE self, VALUE ary, VALUE item) { + return rb_ary_includes(ary, item); +} + +static VALUE array_spec_rb_ary_join(VALUE self, VALUE array1, VALUE array2) { + return rb_ary_join(array1, array2); +} + +static VALUE array_spec_rb_ary_to_s(VALUE self, VALUE array) { + return rb_ary_to_s(array); +} + +static VALUE array_spec_rb_ary_new(VALUE self) { + VALUE ret; + ret = rb_ary_new(); + return ret; +} + +static VALUE array_spec_rb_ary_new2(VALUE self, VALUE length) { + return rb_ary_new2(NUM2LONG(length)); +} + +static VALUE array_spec_rb_ary_new_capa(VALUE self, VALUE length) { + return rb_ary_new_capa(NUM2LONG(length)); +} + +static VALUE array_spec_rb_ary_new3(VALUE self, VALUE first, VALUE second, VALUE third) { + return rb_ary_new3(3, first, second, third); +} + +static VALUE array_spec_rb_ary_new_from_args(VALUE self, VALUE first, VALUE second, VALUE third) { + return rb_ary_new_from_args(3, first, second, third); +} + +static VALUE array_spec_rb_ary_new4(VALUE self, VALUE first, VALUE second, VALUE third) { + VALUE values[3]; + values[0] = first; + values[1] = second; + values[2] = third; + return rb_ary_new4(3, values); +} + +static VALUE array_spec_rb_ary_new_from_values(VALUE self, VALUE first, VALUE second, VALUE third) { + VALUE values[3]; + values[0] = first; + values[1] = second; + values[2] = third; + return rb_ary_new_from_values(3, values); +} + +static VALUE array_spec_rb_ary_pop(VALUE self, VALUE array) { + return rb_ary_pop(array); +} + +static VALUE array_spec_rb_ary_push(VALUE self, VALUE array, VALUE item) { + rb_ary_push(array, item); + return array; +} + +static VALUE array_spec_rb_ary_cat(int argc, VALUE *argv, VALUE self) { + VALUE ary, args; + rb_scan_args(argc, argv, "1*", &ary, &args); + return rb_ary_cat(ary, RARRAY_PTR(args), RARRAY_LEN(args)); +} + +static VALUE array_spec_rb_ary_reverse(VALUE self, VALUE array) { + return rb_ary_reverse(array); +} + +static VALUE array_spec_rb_ary_rotate(VALUE self, VALUE array, VALUE count) { + return rb_ary_rotate(array, NUM2LONG(count)); +} + +static VALUE array_spec_rb_ary_shift(VALUE self, VALUE array) { + return rb_ary_shift(array); +} + +static VALUE array_spec_rb_ary_sort(VALUE self, VALUE array) { + return rb_ary_sort(array); +} + +static VALUE array_spec_rb_ary_sort_bang(VALUE self, VALUE array) { + return rb_ary_sort_bang(array); +} + +static VALUE array_spec_rb_ary_store(VALUE self, VALUE array, VALUE offset, VALUE value) { + rb_ary_store(array, FIX2INT(offset), value); + + return Qnil; +} + +static VALUE array_spec_rb_ary_concat(VALUE self, VALUE array1, VALUE array2) { + return rb_ary_concat(array1, array2); +} + +static VALUE array_spec_rb_ary_plus(VALUE self, VALUE array1, VALUE array2) { + return rb_ary_plus(array1, array2); +} + +static VALUE array_spec_rb_ary_unshift(VALUE self, VALUE array, VALUE val) { + return rb_ary_unshift(array, val); +} + +static VALUE array_spec_rb_assoc_new(VALUE self, VALUE first, VALUE second) { + return rb_assoc_new(first, second); +} + +static VALUE copy_ary(RB_BLOCK_CALL_FUNC_ARGLIST(el, new_ary)) { + return rb_ary_push(new_ary, el); +} + +#ifndef RUBY_VERSION_IS_4_0 +static VALUE array_spec_rb_iterate(VALUE self, VALUE ary) { + VALUE new_ary = rb_ary_new(); + + rb_iterate(rb_each, ary, copy_ary, new_ary); + + return new_ary; +} +#endif + +static VALUE array_spec_rb_block_call(VALUE self, VALUE ary) { + VALUE new_ary = rb_ary_new(); + + rb_block_call(ary, rb_intern("each"), 0, 0, copy_ary, new_ary); + + return new_ary; +} + +static VALUE sub_pair(RB_BLOCK_CALL_FUNC_ARGLIST(el, holder)) { + return rb_ary_push(holder, rb_ary_entry(el, 1)); +} + +#ifndef RUBY_VERSION_IS_4_0 +static VALUE each_pair(VALUE obj) { + return rb_funcall(obj, rb_intern("each_pair"), 0); +} + +static VALUE array_spec_rb_iterate_each_pair(VALUE self, VALUE obj) { + VALUE new_ary = rb_ary_new(); + + rb_iterate(each_pair, obj, sub_pair, new_ary); + + return new_ary; +} +#endif + +static VALUE array_spec_rb_block_call_each_pair(VALUE self, VALUE obj) { + VALUE new_ary = rb_ary_new(); + + rb_block_call(obj, rb_intern("each_pair"), 0, 0, sub_pair, new_ary); + + return new_ary; +} + +static VALUE iter_yield(RB_BLOCK_CALL_FUNC_ARGLIST(el, ary)) { + rb_yield(el); + return Qnil; +} + +#ifndef RUBY_VERSION_IS_4_0 +static VALUE array_spec_rb_iterate_then_yield(VALUE self, VALUE obj) { + rb_iterate(rb_each, obj, iter_yield, obj); + return Qnil; +} +#endif + +static VALUE array_spec_rb_block_call_then_yield(VALUE self, VALUE obj) { + rb_block_call(obj, rb_intern("each"), 0, 0, iter_yield, obj); + return Qnil; +} + +static VALUE array_spec_rb_mem_clear(VALUE self, VALUE obj) { + VALUE ary[1]; + ary[0] = obj; + rb_mem_clear(ary, 1); + return ary[0]; +} + +static VALUE array_spec_rb_ary_freeze(VALUE self, VALUE ary) { + return rb_ary_freeze(ary); +} + +static VALUE array_spec_rb_ary_to_ary(VALUE self, VALUE ary) { + return rb_ary_to_ary(ary); +} + +static VALUE array_spec_rb_ary_subseq(VALUE self, VALUE ary, VALUE begin, VALUE len) { + return rb_ary_subseq(ary, FIX2LONG(begin), FIX2LONG(len)); +} + +void Init_array_spec(void) { + VALUE cls = rb_define_class("CApiArraySpecs", rb_cObject); + rb_define_method(cls, "rb_Array", array_spec_rb_Array, 1); + rb_define_method(cls, "RARRAY_LEN", array_spec_RARRAY_LEN, 1); + rb_define_method(cls, "RARRAY_PTR_iterate", array_spec_RARRAY_PTR_iterate, 1); + rb_define_method(cls, "RARRAY_PTR_assign", array_spec_RARRAY_PTR_assign, 2); + rb_define_method(cls, "RARRAY_PTR_memcpy", array_spec_RARRAY_PTR_memcpy, 2); + rb_define_method(cls, "RARRAY_AREF", array_spec_RARRAY_AREF, 2); + rb_define_method(cls, "RARRAY_ASET", array_spec_RARRAY_ASET, 3); + rb_define_method(cls, "rb_ary_aref", array_spec_rb_ary_aref, -1); + rb_define_method(cls, "rb_ary_clear", array_spec_rb_ary_clear, 1); + rb_define_method(cls, "rb_ary_delete", array_spec_rb_ary_delete, 2); + rb_define_method(cls, "rb_ary_delete_at", array_spec_rb_ary_delete_at, 2); + rb_define_method(cls, "rb_ary_dup", array_spec_rb_ary_dup, 1); + rb_define_method(cls, "rb_ary_entry", array_spec_rb_ary_entry, 2); + rb_define_method(cls, "rb_ary_includes", array_spec_rb_ary_includes, 2); + rb_define_method(cls, "rb_ary_join", array_spec_rb_ary_join, 2); + rb_define_method(cls, "rb_ary_to_s", array_spec_rb_ary_to_s, 1); + rb_define_method(cls, "rb_ary_new", array_spec_rb_ary_new, 0); + rb_define_method(cls, "rb_ary_new2", array_spec_rb_ary_new2, 1); + rb_define_method(cls, "rb_ary_new_capa", array_spec_rb_ary_new_capa, 1); + rb_define_method(cls, "rb_ary_new3", array_spec_rb_ary_new3, 3); + rb_define_method(cls, "rb_ary_new_from_args", array_spec_rb_ary_new_from_args, 3); + rb_define_method(cls, "rb_ary_new4", array_spec_rb_ary_new4, 3); + rb_define_method(cls, "rb_ary_new_from_values", array_spec_rb_ary_new_from_values, 3); + rb_define_method(cls, "rb_ary_pop", array_spec_rb_ary_pop, 1); + rb_define_method(cls, "rb_ary_push", array_spec_rb_ary_push, 2); + rb_define_method(cls, "rb_ary_cat", array_spec_rb_ary_cat, -1); + rb_define_method(cls, "rb_ary_reverse", array_spec_rb_ary_reverse, 1); + rb_define_method(cls, "rb_ary_rotate", array_spec_rb_ary_rotate, 2); + rb_define_method(cls, "rb_ary_shift", array_spec_rb_ary_shift, 1); + rb_define_method(cls, "rb_ary_sort", array_spec_rb_ary_sort, 1); + rb_define_method(cls, "rb_ary_sort_bang", array_spec_rb_ary_sort_bang, 1); + rb_define_method(cls, "rb_ary_store", array_spec_rb_ary_store, 3); + rb_define_method(cls, "rb_ary_concat", array_spec_rb_ary_concat, 2); + rb_define_method(cls, "rb_ary_plus", array_spec_rb_ary_plus, 2); + rb_define_method(cls, "rb_ary_unshift", array_spec_rb_ary_unshift, 2); + rb_define_method(cls, "rb_assoc_new", array_spec_rb_assoc_new, 2); +#ifndef RUBY_VERSION_IS_4_0 + rb_define_method(cls, "rb_iterate", array_spec_rb_iterate, 1); + rb_define_method(cls, "rb_iterate_each_pair", array_spec_rb_iterate_each_pair, 1); + rb_define_method(cls, "rb_iterate_then_yield", array_spec_rb_iterate_then_yield, 1); +#endif + rb_define_method(cls, "rb_block_call", array_spec_rb_block_call, 1); + rb_define_method(cls, "rb_block_call_each_pair", array_spec_rb_block_call_each_pair, 1); + rb_define_method(cls, "rb_block_call_then_yield", array_spec_rb_block_call_then_yield, 1); + rb_define_method(cls, "rb_mem_clear", array_spec_rb_mem_clear, 1); + rb_define_method(cls, "rb_ary_freeze", array_spec_rb_ary_freeze, 1); + rb_define_method(cls, "rb_ary_to_ary", array_spec_rb_ary_to_ary, 1); + rb_define_method(cls, "rb_ary_subseq", array_spec_rb_ary_subseq, 3); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/basic_object_spec.c b/spec/ruby/optional/capi/ext/basic_object_spec.c new file mode 100644 index 0000000000..1618670ceb --- /dev/null +++ b/spec/ruby/optional/capi/ext/basic_object_spec.c @@ -0,0 +1,19 @@ +#include "ruby.h" +#include "rubyspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static VALUE basic_object_spec_RBASIC_CLASS(VALUE self, VALUE obj) { + return RBASIC_CLASS(obj); +} + +void Init_basic_object_spec(void) { + VALUE cls = rb_define_class("CApiBasicObjectSpecs", rb_cObject); + rb_define_method(cls, "RBASIC_CLASS", basic_object_spec_RBASIC_CLASS, 1); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/bignum_spec.c b/spec/ruby/optional/capi/ext/bignum_spec.c new file mode 100644 index 0000000000..a950d8b16f --- /dev/null +++ b/spec/ruby/optional/capi/ext/bignum_spec.c @@ -0,0 +1,106 @@ +#include "ruby.h" +#include "rubyspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static VALUE bignum_spec_rb_big2dbl(VALUE self, VALUE num) { + return rb_float_new(rb_big2dbl(num)); +} + +static VALUE bignum_spec_rb_dbl2big(VALUE self, VALUE num) { + double dnum = NUM2DBL(num); + + return rb_dbl2big(dnum); +} + +static VALUE bignum_spec_rb_big2ll(VALUE self, VALUE num) { + return rb_ll2inum(rb_big2ll(num)); +} + +static VALUE bignum_spec_rb_big2long(VALUE self, VALUE num) { + return LONG2NUM(rb_big2long(num)); +} + +static VALUE bignum_spec_rb_big2str(VALUE self, VALUE num, VALUE base) { + return rb_big2str(num, FIX2INT(base)); +} + +static VALUE bignum_spec_rb_big2ulong(VALUE self, VALUE num) { + return ULONG2NUM(rb_big2ulong(num)); +} + +static VALUE bignum_spec_RBIGNUM_SIGN(VALUE self, VALUE val) { + return INT2FIX(RBIGNUM_SIGN(val)); +} + +static VALUE bignum_spec_rb_big_cmp(VALUE self, VALUE x, VALUE y) { + return rb_big_cmp(x, y); +} + +static VALUE bignum_spec_rb_big_pack(VALUE self, VALUE val) { + unsigned long buff; + + rb_big_pack(val, &buff, 1); + + return ULONG2NUM(buff); +} + +static VALUE bignum_spec_rb_big_pack_length(VALUE self, VALUE val) { + long long_len; + int leading_bits = 0; + int divisor = SIZEOF_LONG; + size_t len = rb_absint_size(val, &leading_bits); + if (leading_bits == 0) { + len += 1; + } + + long_len = len / divisor + ((len % divisor == 0) ? 0 : 1); + return LONG2NUM(long_len); +} + +static VALUE bignum_spec_rb_big_pack_array(VALUE self, VALUE val, VALUE len) { + int i; + long long_len = NUM2LONG(len); + + VALUE ary = rb_ary_new_capa(long_len); + unsigned long *buf = (unsigned long*) malloc(long_len * SIZEOF_LONG); + + /* The array should be filled with recognisable junk so we can check + it is all cleared properly. */ + + for (i = 0; i < long_len; i++) { +#if SIZEOF_LONG == 8 + buf[i] = 0xfedcba9876543210L; +#else + buf[i] = 0xfedcba98L; +#endif + } + + rb_big_pack(val, buf, long_len); + for (i = 0; i < long_len; i++) { + rb_ary_store(ary, i, ULONG2NUM(buf[i])); + } + free(buf); + return ary; +} + +void Init_bignum_spec(void) { + VALUE cls = rb_define_class("CApiBignumSpecs", rb_cObject); + rb_define_method(cls, "rb_big2dbl", bignum_spec_rb_big2dbl, 1); + rb_define_method(cls, "rb_dbl2big", bignum_spec_rb_dbl2big, 1); + rb_define_method(cls, "rb_big2ll", bignum_spec_rb_big2ll, 1); + rb_define_method(cls, "rb_big2long", bignum_spec_rb_big2long, 1); + rb_define_method(cls, "rb_big2str", bignum_spec_rb_big2str, 2); + rb_define_method(cls, "rb_big2ulong", bignum_spec_rb_big2ulong, 1); + rb_define_method(cls, "RBIGNUM_SIGN", bignum_spec_RBIGNUM_SIGN, 1); + rb_define_method(cls, "rb_big_cmp", bignum_spec_rb_big_cmp, 2); + rb_define_method(cls, "rb_big_pack", bignum_spec_rb_big_pack, 1); + rb_define_method(cls, "rb_big_pack_array", bignum_spec_rb_big_pack_array, 2); + rb_define_method(cls, "rb_big_pack_length", bignum_spec_rb_big_pack_length, 1); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/binding_spec.c b/spec/ruby/optional/capi/ext/binding_spec.c new file mode 100644 index 0000000000..b2e3c88b6d --- /dev/null +++ b/spec/ruby/optional/capi/ext/binding_spec.c @@ -0,0 +1,19 @@ +#include "ruby.h" +#include "rubyspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static VALUE binding_spec_get_binding(VALUE self) { + return rb_funcall(self, rb_intern("binding"), 0); +} + +void Init_binding_spec(void) { + VALUE cls = rb_define_class("CApiBindingSpecs", rb_cObject); + rb_define_method(cls, "get_binding", binding_spec_get_binding, 0); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/boolean_spec.c b/spec/ruby/optional/capi/ext/boolean_spec.c new file mode 100644 index 0000000000..081cffa103 --- /dev/null +++ b/spec/ruby/optional/capi/ext/boolean_spec.c @@ -0,0 +1,33 @@ +#include "ruby.h" +#include "rubyspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static VALUE boolean_spec_is_true(VALUE self, VALUE boolean) { + if (boolean) { + return INT2NUM(1); + } else { + return INT2NUM(2); + } +} + +static VALUE boolean_spec_q_true(VALUE self) { + return Qtrue; +} + +static VALUE boolean_spec_q_false(VALUE self) { + return Qfalse; +} + +void Init_boolean_spec(void) { + VALUE cls = rb_define_class("CApiBooleanSpecs", rb_cObject); + rb_define_method(cls, "is_true", boolean_spec_is_true, 1); + rb_define_method(cls, "q_true", boolean_spec_q_true, 0); + rb_define_method(cls, "q_false", boolean_spec_q_false, 0); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/class_id_under_autoload_spec.c b/spec/ruby/optional/capi/ext/class_id_under_autoload_spec.c new file mode 100644 index 0000000000..cc5550f041 --- /dev/null +++ b/spec/ruby/optional/capi/ext/class_id_under_autoload_spec.c @@ -0,0 +1,13 @@ +#include "ruby.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void Init_class_id_under_autoload_spec(void) { + rb_define_class_id_under(rb_cObject, rb_intern("ClassIdUnderAutoload"), rb_cObject); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/class_spec.c b/spec/ruby/optional/capi/ext/class_spec.c new file mode 100644 index 0000000000..8ac0e7a93f --- /dev/null +++ b/spec/ruby/optional/capi/ext/class_spec.c @@ -0,0 +1,180 @@ +#include "ruby.h" +#include "rubyspec.h" + +#include <stdio.h> +#include <string.h> + +#ifdef __cplusplus +extern "C" { +#endif + +static VALUE class_spec_call_super_method(VALUE self) { + return rb_call_super(0, 0); +} + +static VALUE class_spec_define_call_super_method(VALUE self, VALUE obj, VALUE str_name) { + rb_define_method(obj, RSTRING_PTR(str_name), class_spec_call_super_method, 0); + return Qnil; +} + +static VALUE class_spec_rb_class_path(VALUE self, VALUE klass) { + return rb_class_path(klass); +} + +static VALUE class_spec_rb_class_name(VALUE self, VALUE klass) { + return rb_class_name(klass); +} + +static VALUE class_spec_rb_class2name(VALUE self, VALUE klass) { + return rb_str_new2( rb_class2name(klass) ); +} + +static VALUE class_spec_rb_path2class(VALUE self, VALUE path) { + return rb_path2class(RSTRING_PTR(path)); +} + +static VALUE class_spec_rb_path_to_class(VALUE self, VALUE path) { + return rb_path_to_class(path); +} + +static VALUE class_spec_rb_class_instance_methods(int argc, VALUE* argv, VALUE self) { + VALUE mod = argv[0]; + return rb_class_instance_methods(--argc, ++argv, mod); +} + +static VALUE class_spec_rb_class_public_instance_methods(int argc, VALUE* argv, VALUE self) { + VALUE mod = argv[0]; + return rb_class_public_instance_methods(--argc, ++argv, mod); +} + +static VALUE class_spec_rb_class_protected_instance_methods(int argc, VALUE* argv, VALUE self) { + VALUE mod = argv[0]; + return rb_class_protected_instance_methods(--argc, ++argv, mod); +} + +static VALUE class_spec_rb_class_private_instance_methods(int argc, VALUE* argv, VALUE self) { + VALUE mod = argv[0]; + return rb_class_private_instance_methods(--argc, ++argv, mod); +} + +static VALUE class_spec_rb_class_new(VALUE self, VALUE super) { + return rb_class_new(super); +} + +static VALUE class_spec_rb_class_new_instance(VALUE self, VALUE args, VALUE klass) { + return rb_class_new_instance(RARRAY_LENINT(args), RARRAY_PTR(args), klass); +} + +static VALUE class_spec_rb_class_new_instance_kw(VALUE self, VALUE args, VALUE klass) { + return rb_class_new_instance_kw(RARRAY_LENINT(args), RARRAY_PTR(args), klass, RB_PASS_KEYWORDS); +} + +static VALUE class_spec_rb_class_real(VALUE self, VALUE object) { + if (rb_type_p(object, T_FIXNUM)) { + return INT2FIX(rb_class_real(FIX2INT(object))); + } else { + return rb_class_real(CLASS_OF(object)); + } +} + +static VALUE class_spec_rb_class_get_superclass(VALUE self, VALUE klass) { + return rb_class_get_superclass(klass); +} + +static VALUE class_spec_rb_class_superclass(VALUE self, VALUE klass) { + return rb_class_superclass(klass); +} + +static VALUE class_spec_cvar_defined(VALUE self, VALUE klass, VALUE id) { + ID as_id = rb_intern(StringValuePtr(id)); + return rb_cvar_defined(klass, as_id); +} + +static VALUE class_spec_cvar_get(VALUE self, VALUE klass, VALUE name) { + return rb_cvar_get(klass, rb_intern(StringValuePtr(name))); +} + +static VALUE class_spec_cvar_set(VALUE self, VALUE klass, VALUE name, VALUE val) { + rb_cvar_set(klass, rb_intern(StringValuePtr(name)), val); + return Qnil; +} + +static VALUE class_spec_cv_get(VALUE self, VALUE klass, VALUE name) { + return rb_cv_get(klass, StringValuePtr(name)); +} + +static VALUE class_spec_cv_set(VALUE self, VALUE klass, VALUE name, VALUE val) { + rb_cv_set(klass, StringValuePtr(name), val); + + return Qnil; +} + +VALUE class_spec_define_attr(VALUE self, VALUE klass, VALUE sym, VALUE read, VALUE write) { + int int_read, int_write; + int_read = read == Qtrue ? 1 : 0; + int_write = write == Qtrue ? 1 : 0; + rb_define_attr(klass, rb_id2name(SYM2ID(sym)), int_read, int_write); + return Qnil; +} + +static VALUE class_spec_rb_define_class(VALUE self, VALUE name, VALUE super) { + if (NIL_P(super)) super = 0; + return rb_define_class(RSTRING_PTR(name), super); +} + +static VALUE class_spec_rb_define_class_under(VALUE self, VALUE outer, + VALUE name, VALUE super) { + if (NIL_P(super)) super = 0; + return rb_define_class_under(outer, RSTRING_PTR(name), super); +} + +static VALUE class_spec_rb_define_class_id_under(VALUE self, VALUE outer, + VALUE name, VALUE super) { + if (NIL_P(super)) super = 0; + return rb_define_class_id_under(outer, SYM2ID(name), super); +} + +static VALUE class_spec_define_class_variable(VALUE self, VALUE klass, VALUE name, VALUE val) { + rb_define_class_variable(klass, StringValuePtr(name), val); + return Qnil; +} + +static VALUE class_spec_include_module(VALUE self, VALUE klass, VALUE module) { + rb_include_module(klass, module); + return klass; +} + +void Init_class_spec(void) { + VALUE cls = rb_define_class("CApiClassSpecs", rb_cObject); + rb_define_method(cls, "define_call_super_method", class_spec_define_call_super_method, 2); + rb_define_method(cls, "rb_class_path", class_spec_rb_class_path, 1); + rb_define_method(cls, "rb_class_name", class_spec_rb_class_name, 1); + rb_define_method(cls, "rb_class2name", class_spec_rb_class2name, 1); + rb_define_method(cls, "rb_path2class", class_spec_rb_path2class, 1); + rb_define_method(cls, "rb_path_to_class", class_spec_rb_path_to_class, 1); + rb_define_method(cls, "rb_class_instance_methods", class_spec_rb_class_instance_methods, -1); + rb_define_method(cls, "rb_class_public_instance_methods", class_spec_rb_class_public_instance_methods, -1); + rb_define_method(cls, "rb_class_protected_instance_methods", class_spec_rb_class_protected_instance_methods, -1); + rb_define_method(cls, "rb_class_private_instance_methods", class_spec_rb_class_private_instance_methods, -1); + rb_define_method(cls, "rb_class_new", class_spec_rb_class_new, 1); + rb_define_method(cls, "rb_class_new_instance", class_spec_rb_class_new_instance, 2); + rb_define_method(cls, "rb_class_new_instance_kw", class_spec_rb_class_new_instance_kw, 2); + rb_define_method(cls, "rb_class_real", class_spec_rb_class_real, 1); + rb_define_method(cls, "rb_class_get_superclass", class_spec_rb_class_get_superclass, 1); + rb_define_method(cls, "rb_class_superclass", class_spec_rb_class_superclass, 1); + rb_define_method(cls, "rb_cvar_defined", class_spec_cvar_defined, 2); + rb_define_method(cls, "rb_cvar_get", class_spec_cvar_get, 2); + rb_define_method(cls, "rb_cvar_set", class_spec_cvar_set, 3); + rb_define_method(cls, "rb_cv_get", class_spec_cv_get, 2); + rb_define_method(cls, "rb_cv_set", class_spec_cv_set, 3); + rb_define_method(cls, "rb_define_attr", class_spec_define_attr, 4); + rb_define_method(cls, "rb_define_class", class_spec_rb_define_class, 2); + rb_define_method(cls, "rb_define_class_under", class_spec_rb_define_class_under, 3); + rb_define_method(cls, "rb_define_class_id_under", class_spec_rb_define_class_id_under, 3); + rb_define_method(cls, "rb_define_class_variable", class_spec_define_class_variable, 3); + rb_define_method(cls, "rb_include_module", class_spec_include_module, 2); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/class_under_autoload_spec.c b/spec/ruby/optional/capi/ext/class_under_autoload_spec.c new file mode 100644 index 0000000000..e0b1f249c0 --- /dev/null +++ b/spec/ruby/optional/capi/ext/class_under_autoload_spec.c @@ -0,0 +1,13 @@ +#include "ruby.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void Init_class_under_autoload_spec(void) { + rb_define_class_under(rb_cObject, "ClassUnderAutoload", rb_cObject); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/complex_spec.c b/spec/ruby/optional/capi/ext/complex_spec.c new file mode 100644 index 0000000000..dfccd7a037 --- /dev/null +++ b/spec/ruby/optional/capi/ext/complex_spec.c @@ -0,0 +1,45 @@ +#include "ruby.h" +#include "rubyspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static VALUE complex_spec_rb_Complex(VALUE self, VALUE num, VALUE den) { + return rb_Complex(num, den); +} + +static VALUE complex_spec_rb_Complex1(VALUE self, VALUE num) { + return rb_Complex1(num); +} + +static VALUE complex_spec_rb_Complex2(VALUE self, VALUE num, VALUE den) { + return rb_Complex2(num, den); +} + +static VALUE complex_spec_rb_complex_new(VALUE self, VALUE num, VALUE den) { + return rb_complex_new(num, den); +} + +static VALUE complex_spec_rb_complex_new1(VALUE self, VALUE num) { + return rb_complex_new1(num); +} + +static VALUE complex_spec_rb_complex_new2(VALUE self, VALUE num, VALUE den) { + return rb_complex_new2(num, den); +} + +void Init_complex_spec(void) { + VALUE cls = rb_define_class("CApiComplexSpecs", rb_cObject); + rb_define_method(cls, "rb_Complex", complex_spec_rb_Complex, 2); + rb_define_method(cls, "rb_Complex1", complex_spec_rb_Complex1, 1); + rb_define_method(cls, "rb_Complex2", complex_spec_rb_Complex2, 2); + rb_define_method(cls, "rb_complex_new", complex_spec_rb_complex_new, 2); + rb_define_method(cls, "rb_complex_new1", complex_spec_rb_complex_new1, 1); + rb_define_method(cls, "rb_complex_new2", complex_spec_rb_complex_new2, 2); +} + +#ifdef __cplusplus +} +#endif + diff --git a/spec/ruby/optional/capi/ext/constants_spec.c b/spec/ruby/optional/capi/ext/constants_spec.c new file mode 100644 index 0000000000..05819ea476 --- /dev/null +++ b/spec/ruby/optional/capi/ext/constants_spec.c @@ -0,0 +1,172 @@ +#include "ruby.h" +#include "rubyspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define defconstfunc(name) \ +static VALUE constants_spec_##name(VALUE self) { return name; } + +defconstfunc(rb_cArray) +defconstfunc(rb_cBasicObject) +defconstfunc(rb_cBinding) +defconstfunc(rb_cClass) +defconstfunc(rb_cComplex) +defconstfunc(rb_mComparable) +defconstfunc(rb_cDir) +defconstfunc(rb_cEncoding) +defconstfunc(rb_mEnumerable) +defconstfunc(rb_cEnumerator) +defconstfunc(rb_cFalseClass) +defconstfunc(rb_cFile) +defconstfunc(rb_mFileTest) +defconstfunc(rb_cFloat) +defconstfunc(rb_mGC) +defconstfunc(rb_cHash) +defconstfunc(rb_cInteger) +defconstfunc(rb_cIO) +defconstfunc(rb_mKernel) +defconstfunc(rb_mMath) +defconstfunc(rb_cMatch) +defconstfunc(rb_cMethod) +defconstfunc(rb_cModule) +defconstfunc(rb_cNilClass) +defconstfunc(rb_cNumeric) +defconstfunc(rb_cObject) +defconstfunc(rb_cProc) +defconstfunc(rb_mProcess) +defconstfunc(rb_cRandom) +defconstfunc(rb_cRange) +defconstfunc(rb_cRational) +defconstfunc(rb_cRegexp) +defconstfunc(rb_cStat) +defconstfunc(rb_cString) +defconstfunc(rb_cStruct) +defconstfunc(rb_cSymbol) +defconstfunc(rb_cTime) +defconstfunc(rb_cThread) +defconstfunc(rb_cTrueClass) +defconstfunc(rb_cUnboundMethod) +defconstfunc(rb_eArgError) +defconstfunc(rb_eEncodingError) +defconstfunc(rb_eEncCompatError) +defconstfunc(rb_eEOFError) +defconstfunc(rb_mErrno) +defconstfunc(rb_eException) +defconstfunc(rb_eFatal) +defconstfunc(rb_eFloatDomainError) +defconstfunc(rb_eFrozenError) +defconstfunc(rb_eIndexError) +defconstfunc(rb_eInterrupt) +defconstfunc(rb_eIOError) +defconstfunc(rb_eKeyError) +defconstfunc(rb_eLoadError) +defconstfunc(rb_eLocalJumpError) +defconstfunc(rb_eMathDomainError) +defconstfunc(rb_eNameError) +defconstfunc(rb_eNoMemError) +defconstfunc(rb_eNoMethodError) +defconstfunc(rb_eNotImpError) +defconstfunc(rb_eRangeError) +defconstfunc(rb_eRegexpError) +defconstfunc(rb_eRuntimeError) +defconstfunc(rb_eScriptError) +defconstfunc(rb_eSecurityError) +defconstfunc(rb_eSignal) +defconstfunc(rb_eStandardError) +defconstfunc(rb_eStopIteration) +defconstfunc(rb_eSyntaxError) +defconstfunc(rb_eSystemCallError) +defconstfunc(rb_eSystemExit) +defconstfunc(rb_eSysStackError) +defconstfunc(rb_eTypeError) +defconstfunc(rb_eThreadError) +defconstfunc(rb_mWaitReadable) +defconstfunc(rb_mWaitWritable) +defconstfunc(rb_eZeroDivError) + +void Init_constants_spec(void) { + VALUE cls = rb_define_class("CApiConstantsSpecs", rb_cObject); + rb_define_method(cls, "rb_cArray", constants_spec_rb_cArray, 0); + rb_define_method(cls, "rb_cBasicObject", constants_spec_rb_cBasicObject, 0); + rb_define_method(cls, "rb_cBinding", constants_spec_rb_cBinding, 0); + rb_define_method(cls, "rb_cClass", constants_spec_rb_cClass, 0); + rb_define_method(cls, "rb_cComplex", constants_spec_rb_cComplex, 0); + rb_define_method(cls, "rb_mComparable", constants_spec_rb_mComparable, 0); + rb_define_method(cls, "rb_cDir", constants_spec_rb_cDir, 0); + rb_define_method(cls, "rb_cEncoding", constants_spec_rb_cEncoding, 0); + rb_define_method(cls, "rb_mEnumerable", constants_spec_rb_mEnumerable, 0); + rb_define_method(cls, "rb_cEnumerator", constants_spec_rb_cEnumerator, 0); + rb_define_method(cls, "rb_cFalseClass", constants_spec_rb_cFalseClass, 0); + rb_define_method(cls, "rb_cFile", constants_spec_rb_cFile, 0); + rb_define_method(cls, "rb_mFileTest", constants_spec_rb_mFileTest, 0); + rb_define_method(cls, "rb_cFloat", constants_spec_rb_cFloat, 0); + rb_define_method(cls, "rb_mGC", constants_spec_rb_mGC, 0); + rb_define_method(cls, "rb_cHash", constants_spec_rb_cHash, 0); + rb_define_method(cls, "rb_cInteger", constants_spec_rb_cInteger, 0); + rb_define_method(cls, "rb_cIO", constants_spec_rb_cIO, 0); + rb_define_method(cls, "rb_mKernel", constants_spec_rb_mKernel, 0); + rb_define_method(cls, "rb_mMath", constants_spec_rb_mMath, 0); + rb_define_method(cls, "rb_cMatch", constants_spec_rb_cMatch, 0); + rb_define_method(cls, "rb_cMethod", constants_spec_rb_cMethod, 0); + rb_define_method(cls, "rb_cModule", constants_spec_rb_cModule, 0); + rb_define_method(cls, "rb_cNilClass", constants_spec_rb_cNilClass, 0); + rb_define_method(cls, "rb_cNumeric", constants_spec_rb_cNumeric, 0); + rb_define_method(cls, "rb_cObject", constants_spec_rb_cObject, 0); + rb_define_method(cls, "rb_cProc", constants_spec_rb_cProc, 0); + rb_define_method(cls, "rb_mProcess", constants_spec_rb_mProcess, 0); + rb_define_method(cls, "rb_cRandom", constants_spec_rb_cRandom, 0); + rb_define_method(cls, "rb_cRange", constants_spec_rb_cRange, 0); + rb_define_method(cls, "rb_cRational", constants_spec_rb_cRational, 0); + rb_define_method(cls, "rb_cRegexp", constants_spec_rb_cRegexp, 0); + rb_define_method(cls, "rb_cStat", constants_spec_rb_cStat, 0); + rb_define_method(cls, "rb_cString", constants_spec_rb_cString, 0); + rb_define_method(cls, "rb_cStruct", constants_spec_rb_cStruct, 0); + rb_define_method(cls, "rb_cSymbol", constants_spec_rb_cSymbol, 0); + rb_define_method(cls, "rb_cTime", constants_spec_rb_cTime, 0); + rb_define_method(cls, "rb_cThread", constants_spec_rb_cThread, 0); + rb_define_method(cls, "rb_cTrueClass", constants_spec_rb_cTrueClass, 0); + rb_define_method(cls, "rb_cUnboundMethod", constants_spec_rb_cUnboundMethod, 0); + rb_define_method(cls, "rb_eArgError", constants_spec_rb_eArgError, 0); + rb_define_method(cls, "rb_eEncodingError", constants_spec_rb_eEncodingError, 0); + rb_define_method(cls, "rb_eEncCompatError", constants_spec_rb_eEncCompatError, 0); + rb_define_method(cls, "rb_eEOFError", constants_spec_rb_eEOFError, 0); + rb_define_method(cls, "rb_mErrno", constants_spec_rb_mErrno, 0); + rb_define_method(cls, "rb_eException", constants_spec_rb_eException, 0); + rb_define_method(cls, "rb_eFatal", constants_spec_rb_eFatal, 0); + rb_define_method(cls, "rb_eFloatDomainError", constants_spec_rb_eFloatDomainError, 0); + rb_define_method(cls, "rb_eFrozenError", constants_spec_rb_eFrozenError, 0); + rb_define_method(cls, "rb_eIndexError", constants_spec_rb_eIndexError, 0); + rb_define_method(cls, "rb_eInterrupt", constants_spec_rb_eInterrupt, 0); + rb_define_method(cls, "rb_eIOError", constants_spec_rb_eIOError, 0); + rb_define_method(cls, "rb_eKeyError", constants_spec_rb_eKeyError, 0); + rb_define_method(cls, "rb_eLoadError", constants_spec_rb_eLoadError, 0); + rb_define_method(cls, "rb_eLocalJumpError", constants_spec_rb_eLocalJumpError, 0); + rb_define_method(cls, "rb_eMathDomainError", constants_spec_rb_eMathDomainError, 0); + rb_define_method(cls, "rb_eNameError", constants_spec_rb_eNameError, 0); + rb_define_method(cls, "rb_eNoMemError", constants_spec_rb_eNoMemError, 0); + rb_define_method(cls, "rb_eNoMethodError", constants_spec_rb_eNoMethodError, 0); + rb_define_method(cls, "rb_eNotImpError", constants_spec_rb_eNotImpError, 0); + rb_define_method(cls, "rb_eRangeError", constants_spec_rb_eRangeError, 0); + rb_define_method(cls, "rb_eRegexpError", constants_spec_rb_eRegexpError, 0); + rb_define_method(cls, "rb_eRuntimeError", constants_spec_rb_eRuntimeError, 0); + rb_define_method(cls, "rb_eScriptError", constants_spec_rb_eScriptError, 0); + rb_define_method(cls, "rb_eSecurityError", constants_spec_rb_eSecurityError, 0); + rb_define_method(cls, "rb_eSignal", constants_spec_rb_eSignal, 0); + rb_define_method(cls, "rb_eStandardError", constants_spec_rb_eStandardError, 0); + rb_define_method(cls, "rb_eStopIteration", constants_spec_rb_eStopIteration, 0); + rb_define_method(cls, "rb_eSyntaxError", constants_spec_rb_eSyntaxError, 0); + rb_define_method(cls, "rb_eSystemCallError", constants_spec_rb_eSystemCallError, 0); + rb_define_method(cls, "rb_eSystemExit", constants_spec_rb_eSystemExit, 0); + rb_define_method(cls, "rb_eSysStackError", constants_spec_rb_eSysStackError, 0); + rb_define_method(cls, "rb_eTypeError", constants_spec_rb_eTypeError, 0); + rb_define_method(cls, "rb_eThreadError", constants_spec_rb_eThreadError, 0); + rb_define_method(cls, "rb_mWaitReadable", constants_spec_rb_mWaitReadable, 0); + rb_define_method(cls, "rb_mWaitWritable", constants_spec_rb_mWaitWritable, 0); + rb_define_method(cls, "rb_eZeroDivError", constants_spec_rb_eZeroDivError, 0); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/data_spec.c b/spec/ruby/optional/capi/ext/data_spec.c new file mode 100644 index 0000000000..efefe37c3a --- /dev/null +++ b/spec/ruby/optional/capi/ext/data_spec.c @@ -0,0 +1,93 @@ +#include "ruby.h" +#include "rubyspec.h" + +#include <string.h> + +#ifndef RUBY_VERSION_IS_3_4 +#ifdef __cplusplus +extern "C" { +#endif + +struct sample_wrapped_struct { + int foo; +}; + +void sample_wrapped_struct_free(void* st) { + free(st); +} + +void sample_wrapped_struct_mark(void* st) { +} + +VALUE sdaf_alloc_func(VALUE klass) { + struct sample_wrapped_struct* bar = (struct sample_wrapped_struct*) malloc(sizeof(struct sample_wrapped_struct)); + bar->foo = 42; + return Data_Wrap_Struct(klass, &sample_wrapped_struct_mark, &sample_wrapped_struct_free, bar); +} + +VALUE sdaf_get_struct(VALUE self) { + struct sample_wrapped_struct* bar; + Data_Get_Struct(self, struct sample_wrapped_struct, bar); + + return INT2FIX((*bar).foo); +} + +VALUE sws_wrap_struct(VALUE self, VALUE val) { + struct sample_wrapped_struct* bar = (struct sample_wrapped_struct*) malloc(sizeof(struct sample_wrapped_struct)); + bar->foo = FIX2INT(val); + return Data_Wrap_Struct(rb_cObject, &sample_wrapped_struct_mark, &sample_wrapped_struct_free, bar); +} + +VALUE sws_get_struct(VALUE self, VALUE obj) { + struct sample_wrapped_struct* bar; + Data_Get_Struct(obj, struct sample_wrapped_struct, bar); + + return INT2FIX((*bar).foo); +} + +VALUE sws_get_struct_rdata(VALUE self, VALUE obj) { + struct sample_wrapped_struct* bar; + bar = (struct sample_wrapped_struct*) RDATA(obj)->data; + return INT2FIX(bar->foo); +} + +VALUE sws_get_struct_data_ptr(VALUE self, VALUE obj) { + struct sample_wrapped_struct* bar; + bar = (struct sample_wrapped_struct*) DATA_PTR(obj); + return INT2FIX(bar->foo); +} + +VALUE sws_change_struct(VALUE self, VALUE obj, VALUE new_val) { + struct sample_wrapped_struct *old_struct, *new_struct; + new_struct = (struct sample_wrapped_struct*) malloc(sizeof(struct sample_wrapped_struct)); + new_struct->foo = FIX2INT(new_val); + old_struct = (struct sample_wrapped_struct*) RDATA(obj)->data; + free(old_struct); + RDATA(obj)->data = new_struct; + return Qnil; +} + +VALUE sws_rb_check_type(VALUE self, VALUE obj, VALUE other) { + rb_check_type(obj, TYPE(other)); + return Qtrue; +} +#endif + +void Init_data_spec(void) { +#ifndef RUBY_VERSION_IS_3_4 + VALUE cls = rb_define_class("CApiAllocSpecs", rb_cObject); + rb_define_alloc_func(cls, sdaf_alloc_func); + rb_define_method(cls, "wrapped_data", sdaf_get_struct, 0); + cls = rb_define_class("CApiWrappedStructSpecs", rb_cObject); + rb_define_method(cls, "wrap_struct", sws_wrap_struct, 1); + rb_define_method(cls, "get_struct", sws_get_struct, 1); + rb_define_method(cls, "get_struct_rdata", sws_get_struct_rdata, 1); + rb_define_method(cls, "get_struct_data_ptr", sws_get_struct_data_ptr, 1); + rb_define_method(cls, "change_struct", sws_change_struct, 2); + rb_define_method(cls, "rb_check_type", sws_rb_check_type, 2); +#endif +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/debug_spec.c b/spec/ruby/optional/capi/ext/debug_spec.c new file mode 100644 index 0000000000..9131eda78b --- /dev/null +++ b/spec/ruby/optional/capi/ext/debug_spec.c @@ -0,0 +1,93 @@ +#include "ruby.h" +#include "rubyspec.h" +#include "ruby/debug.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static VALUE callback_data = Qfalse; + +static VALUE rb_debug_inspector_open_callback(const rb_debug_inspector_t *dc, void *ptr) { + if (!dc) { + rb_raise(rb_eRuntimeError, "rb_debug_inspector_t should not be NULL"); + } + + VALUE locations = rb_debug_inspector_backtrace_locations(dc); + int len = RARRAY_LENINT(locations); + VALUE results = rb_ary_new2(len); + for (int i = 0; i < len; i++) { + VALUE ary = rb_ary_new2(5); // [self, klass, binding, iseq, backtrace_location] + rb_ary_store(ary, 0, rb_debug_inspector_frame_self_get(dc, i)); + rb_ary_store(ary, 1, rb_debug_inspector_frame_class_get(dc, i)); + rb_ary_store(ary, 2, rb_debug_inspector_frame_binding_get(dc, i)); + rb_ary_store(ary, 3, rb_debug_inspector_frame_iseq_get(dc, i)); + rb_ary_store(ary, 4, rb_ary_entry(locations, i)); + rb_ary_push(results, ary); + } + callback_data = (VALUE)ptr; + return results; +} + +static VALUE rb_debug_inspector_frame_self_get_callback(const rb_debug_inspector_t *dc, void *ptr) { + return rb_debug_inspector_frame_self_get(dc, NUM2LONG((VALUE) ptr)); +} + +static VALUE rb_debug_inspector_frame_class_get_callback(const rb_debug_inspector_t *dc, void *ptr) { + return rb_debug_inspector_frame_class_get(dc, NUM2LONG((VALUE) ptr)); +} + +static VALUE rb_debug_inspector_frame_binding_get_callback(const rb_debug_inspector_t *dc, void *ptr) { + return rb_debug_inspector_frame_binding_get(dc, NUM2LONG((VALUE) ptr)); +} + +static VALUE rb_debug_inspector_frame_iseq_get_callback(const rb_debug_inspector_t *dc, void *ptr) { + return rb_debug_inspector_frame_iseq_get(dc, NUM2LONG((VALUE) ptr)); +} + +static VALUE debug_spec_callback_data(VALUE self) { + return callback_data; +} + +VALUE debug_spec_rb_debug_inspector_open(VALUE self, VALUE index) { + return rb_debug_inspector_open(rb_debug_inspector_open_callback, (void *)index); +} + +VALUE debug_spec_rb_debug_inspector_frame_self_get(VALUE self, VALUE index) { + return rb_debug_inspector_open(rb_debug_inspector_frame_self_get_callback, (void *)index); +} + +VALUE debug_spec_rb_debug_inspector_frame_class_get(VALUE self, VALUE index) { + return rb_debug_inspector_open(rb_debug_inspector_frame_class_get_callback, (void *)index); +} + +VALUE debug_spec_rb_debug_inspector_frame_binding_get(VALUE self, VALUE index) { + return rb_debug_inspector_open(rb_debug_inspector_frame_binding_get_callback, (void *)index); +} + +VALUE debug_spec_rb_debug_inspector_frame_iseq_get(VALUE self, VALUE index) { + return rb_debug_inspector_open(rb_debug_inspector_frame_iseq_get_callback, (void *)index); +} + +static VALUE rb_debug_inspector_backtrace_locations_func(const rb_debug_inspector_t *dc, void *ptr) { + return rb_debug_inspector_backtrace_locations(dc); +} + +VALUE debug_spec_rb_debug_inspector_backtrace_locations(VALUE self) { + return rb_debug_inspector_open(rb_debug_inspector_backtrace_locations_func, (void *)self); +} + +void Init_debug_spec(void) { + VALUE cls = rb_define_class("CApiDebugSpecs", rb_cObject); + rb_define_method(cls, "rb_debug_inspector_open", debug_spec_rb_debug_inspector_open, 1); + rb_define_method(cls, "rb_debug_inspector_frame_self_get", debug_spec_rb_debug_inspector_frame_self_get, 1); + rb_define_method(cls, "rb_debug_inspector_frame_class_get", debug_spec_rb_debug_inspector_frame_class_get, 1); + rb_define_method(cls, "rb_debug_inspector_frame_binding_get", debug_spec_rb_debug_inspector_frame_binding_get, 1); + rb_define_method(cls, "rb_debug_inspector_frame_iseq_get", debug_spec_rb_debug_inspector_frame_iseq_get, 1); + rb_define_method(cls, "rb_debug_inspector_backtrace_locations", debug_spec_rb_debug_inspector_backtrace_locations, 0); + rb_define_method(cls, "debug_spec_callback_data", debug_spec_callback_data, 0); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/digest_spec.c b/spec/ruby/optional/capi/ext/digest_spec.c new file mode 100644 index 0000000000..65c8defa20 --- /dev/null +++ b/spec/ruby/optional/capi/ext/digest_spec.c @@ -0,0 +1,168 @@ +#include "ruby.h" +#include "rubyspec.h" + +#include "ruby/digest.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define DIGEST_LENGTH 20 +#define BLOCK_LENGTH 40 + +const char *init_string = "Initialized\n"; +const char *update_string = "Updated: "; +const char *finish_string = "Finished\n"; + +#define PAYLOAD_SIZE 128 + +typedef struct CTX { + uint8_t pos; + char payload[PAYLOAD_SIZE]; +} CTX; + +void* context = NULL; + +int digest_spec_plugin_init(void *raw_ctx) { + // Make the context accessible to tests. This isn't safe, but there's no way to access the context otherwise. + context = raw_ctx; + + struct CTX *ctx = (struct CTX *)raw_ctx; + size_t len = strlen(init_string); + + // Clear the payload since this init function will be invoked as part of the `reset` operation. + memset(ctx->payload, 0, PAYLOAD_SIZE); + + // Write a simple value we can verify in tests. + // This is not what a real digest would do, but we're using a dummy digest plugin to test interactions. + memcpy(ctx->payload, init_string, len); + ctx->pos = (uint8_t) len; + + return 1; +} + +void digest_spec_plugin_update(void *raw_ctx, unsigned char *ptr, size_t size) { + struct CTX *ctx = (struct CTX *)raw_ctx; + size_t update_str_len = strlen(update_string); + + if (ctx->pos + update_str_len + size >= PAYLOAD_SIZE) { + rb_raise(rb_eRuntimeError, "update size too large; reset the digest and write fewer updates"); + } + + // Write the supplied value to the payload so it can be easily verified in test. + // This is not what a real digest would do, but we're using a dummy digest plugin to test interactions. + memcpy(ctx->payload + ctx->pos, update_string, update_str_len); + ctx->pos += update_str_len; + + memcpy(ctx->payload + ctx->pos, ptr, size); + ctx->pos += size; + + return; +} + +int digest_spec_plugin_finish(void *raw_ctx, unsigned char *ptr) { + struct CTX *ctx = (struct CTX *)raw_ctx; + size_t finish_string_len = strlen(finish_string); + + // We're always going to write DIGEST_LENGTH bytes. In a real plugin, this would be the digest value. Here we + // write out a text string in order to make validation in tests easier. + // + // In order to delineate the output more clearly from an `Digest#update` call, we always write out the + // `finish_string` message. That leaves `DIGEST_LENGTH - finish_string_len` bytes to read out of the context. + size_t context_bytes = DIGEST_LENGTH - finish_string_len; + + memcpy(ptr, ctx->payload + (ctx->pos - context_bytes), context_bytes); + memcpy(ptr + context_bytes, finish_string, finish_string_len); + + return 1; +} + +static const rb_digest_metadata_t metadata = { + // The RUBY_DIGEST_API_VERSION value comes from ruby/digest.h and may vary based on the Ruby being tested. Since + // it isn't publicly exposed in the digest gem, we ignore for these tests. Either the test hard-codes an expected + // value and is subject to breaking depending on the Ruby being run or we publicly expose `RUBY_DIGEST_API_VERSION`, + // in which case the test would pass trivially. + RUBY_DIGEST_API_VERSION, + DIGEST_LENGTH, + BLOCK_LENGTH, + sizeof(CTX), + (rb_digest_hash_init_func_t) digest_spec_plugin_init, + (rb_digest_hash_update_func_t) digest_spec_plugin_update, + (rb_digest_hash_finish_func_t) digest_spec_plugin_finish, +}; + +// The `get_metadata_ptr` function is not publicly available in the digest gem. However, we need to use +// to extract the `rb_digest_metadata_t*` value set up by the plugin so we reproduce and adjust the +// definition here. +// +// Taken and adapted from https://github.com/ruby/digest/blob/v3.2.0/ext/digest/digest.c#L558-L568 +static rb_digest_metadata_t * get_metadata_ptr(VALUE obj) { + rb_digest_metadata_t *algo; + +#ifdef DIGEST_USE_RB_EXT_RESOLVE_SYMBOL + // In the digest gem there is an additional data type check performed before reading the value out. + // Since the type definition isn't public, we can't use it as part of a type check here so we omit it. + // This is safe to do because this code is intended to only load digest plugins written as part of this test suite. + algo = (rb_digest_metadata_t *) RTYPEDDATA_DATA(obj); +#else +# undef RUBY_UNTYPED_DATA_WARNING +# define RUBY_UNTYPED_DATA_WARNING 0 + Data_Get_Struct(obj, rb_digest_metadata_t, algo); +#endif + + return algo; +} + +VALUE digest_spec_rb_digest_make_metadata(VALUE self) { + return rb_digest_make_metadata(&metadata); +} + +VALUE digest_spec_block_length(VALUE self, VALUE meta) { + rb_digest_metadata_t* algo = get_metadata_ptr(meta); + + return SIZET2NUM(algo->block_len); +} + +VALUE digest_spec_digest_length(VALUE self, VALUE meta) { + rb_digest_metadata_t* algo = get_metadata_ptr(meta); + + return SIZET2NUM(algo->digest_len); +} + +VALUE digest_spec_context_size(VALUE self, VALUE meta) { + rb_digest_metadata_t* algo = get_metadata_ptr(meta); + + return SIZET2NUM(algo->ctx_size); +} + +#ifndef PTR2NUM +#define PTR2NUM(x) (rb_int2inum((intptr_t)(void *)(x))) +#endif + +VALUE digest_spec_context(VALUE self, VALUE digest) { + return PTR2NUM(context); +} + +void Init_digest_spec(void) { + VALUE cls; + + cls = rb_define_class("CApiDigestSpecs", rb_cObject); + rb_define_method(cls, "rb_digest_make_metadata", digest_spec_rb_digest_make_metadata, 0); + rb_define_method(cls, "block_length", digest_spec_block_length, 1); + rb_define_method(cls, "digest_length", digest_spec_digest_length, 1); + rb_define_method(cls, "context_size", digest_spec_context_size, 1); + rb_define_method(cls, "context", digest_spec_context, 1); + + VALUE mDigest, cDigest_Base, cDigest; + + mDigest = rb_define_module("Digest"); + mDigest = rb_digest_namespace(); + cDigest_Base = rb_const_get(mDigest, rb_intern_const("Base")); + + cDigest = rb_define_class_under(mDigest, "TestDigest", cDigest_Base); + rb_iv_set(cDigest, "metadata", rb_digest_make_metadata(&metadata)); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/encoding_spec.c b/spec/ruby/optional/capi/ext/encoding_spec.c new file mode 100644 index 0000000000..aa8662cfbd --- /dev/null +++ b/spec/ruby/optional/capi/ext/encoding_spec.c @@ -0,0 +1,391 @@ +#include "ruby.h" +#include "rubyspec.h" + +#include "ruby/encoding.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static VALUE encoding_spec_MBCLEN_CHARFOUND_P(VALUE self, VALUE obj) { + return INT2FIX(MBCLEN_CHARFOUND_P(FIX2INT(obj))); +} + +static VALUE encoding_spec_ENC_CODERANGE_ASCIIONLY(VALUE self, VALUE obj) { + if (ENC_CODERANGE_ASCIIONLY(obj)) { + return Qtrue; + } else { + return Qfalse; + } +} + +static VALUE encoding_spec_rb_usascii_encoding(VALUE self) { + return rb_str_new2(rb_usascii_encoding()->name); +} + +static VALUE encoding_spec_rb_usascii_encindex(VALUE self) { + return INT2NUM(rb_usascii_encindex()); +} + +static VALUE encoding_spec_rb_ascii8bit_encoding(VALUE self) { + return rb_str_new2(rb_ascii8bit_encoding()->name); +} + +static VALUE encoding_spec_rb_ascii8bit_encindex(VALUE self) { + return INT2NUM(rb_ascii8bit_encindex()); +} + +static VALUE encoding_spec_rb_utf8_encoding(VALUE self) { + return rb_str_new2(rb_utf8_encoding()->name); +} + +static VALUE encoding_spec_rb_utf8_encindex(VALUE self) { + return INT2NUM(rb_utf8_encindex()); +} + +static VALUE encoding_spec_rb_locale_encoding(VALUE self) { + return rb_str_new2(rb_locale_encoding()->name); +} + +static VALUE encoding_spec_rb_locale_encindex(VALUE self) { + return INT2NUM(rb_locale_encindex()); +} + +static VALUE encoding_spec_rb_filesystem_encoding(VALUE self) { + return rb_str_new2(rb_filesystem_encoding()->name); +} + +static VALUE encoding_spec_rb_filesystem_encindex(VALUE self) { + return INT2NUM(rb_filesystem_encindex()); +} + +static VALUE encoding_spec_rb_default_internal_encoding(VALUE self) { + rb_encoding* enc = rb_default_internal_encoding(); + if (enc == 0) return Qnil; + return rb_str_new2(enc->name); +} + +static VALUE encoding_spec_rb_default_external_encoding(VALUE self) { + rb_encoding* enc = rb_default_external_encoding(); + if (enc == 0) return Qnil; + return rb_str_new2(enc->name); +} + +static VALUE encoding_spec_rb_enc_alias(VALUE self, VALUE alias, VALUE orig) { + return INT2NUM(rb_enc_alias(RSTRING_PTR(alias), RSTRING_PTR(orig))); +} + +static VALUE encoding_spec_rb_enc_associate(VALUE self, VALUE obj, VALUE enc) { + return rb_enc_associate(obj, NIL_P(enc) ? NULL : rb_enc_find(RSTRING_PTR(enc))); +} + +static VALUE encoding_spec_rb_enc_associate_index(VALUE self, VALUE obj, VALUE index) { + return rb_enc_associate_index(obj, FIX2INT(index)); +} + +static VALUE encoding_spec_rb_enc_compatible(VALUE self, VALUE a, VALUE b) { + rb_encoding* enc = rb_enc_compatible(a, b); + + if (!enc) return INT2FIX(0); + + return rb_enc_from_encoding(enc); +} + +static VALUE encoding_spec_rb_enc_copy(VALUE self, VALUE dest, VALUE src) { + rb_enc_copy(dest, src); + return dest; +} + +static VALUE encoding_spec_rb_enc_find(VALUE self, VALUE name) { + return rb_str_new2(rb_enc_find(RSTRING_PTR(name))->name); +} + +static VALUE encoding_spec_rb_enc_find_index(VALUE self, VALUE name) { + return INT2NUM(rb_enc_find_index(RSTRING_PTR(name))); +} + +static VALUE encoding_spec_rb_enc_isalnum(VALUE self, VALUE chr, VALUE encoding) { + rb_encoding *e = rb_to_encoding(encoding); + return rb_enc_isalnum(FIX2INT(chr), e) ? Qtrue : Qfalse; +} + +static VALUE encoding_spec_rb_enc_isspace(VALUE self, VALUE chr, VALUE encoding) { + rb_encoding *e = rb_to_encoding(encoding); + return rb_enc_isspace(FIX2INT(chr), e) ? Qtrue : Qfalse; +} + +static VALUE encoding_spec_rb_enc_from_index(VALUE self, VALUE index) { + return rb_str_new2(rb_enc_from_index(NUM2INT(index))->name); +} + +static VALUE encoding_spec_rb_enc_mbc_to_codepoint(VALUE self, VALUE str) { + char *p = RSTRING_PTR(str); + char *e = RSTRING_END(str); + return INT2FIX(rb_enc_mbc_to_codepoint(p, e, rb_enc_get(str))); +} + +static VALUE encoding_spec_rb_enc_mbcput(VALUE self, VALUE code, VALUE encoding) { + unsigned int c = FIX2UINT(code); + rb_encoding *enc = rb_to_encoding(encoding); + char buf[ONIGENC_CODE_TO_MBC_MAXLEN]; + memset(buf, '\1', sizeof(buf)); + int len = rb_enc_mbcput(c, buf, enc); + if (buf[len] != '\1') { + rb_raise(rb_eRuntimeError, "should not change bytes after len"); + } + return rb_enc_str_new(buf, len, enc); +} + +static VALUE encoding_spec_rb_enc_from_encoding(VALUE self, VALUE name) { + return rb_enc_from_encoding(rb_enc_find(RSTRING_PTR(name))); +} + +static VALUE encoding_spec_rb_enc_get(VALUE self, VALUE obj) { + return rb_str_new2(rb_enc_get(obj)->name); +} + +static VALUE encoding_spec_rb_enc_precise_mbclen(VALUE self, VALUE str, VALUE offset) { + int o = FIX2INT(offset); + char *p = RSTRING_PTR(str); + char *e = p + o; + return INT2FIX(rb_enc_precise_mbclen(p, e, rb_enc_get(str))); +} + +static VALUE encoding_spec_rb_obj_encoding(VALUE self, VALUE obj) { + return rb_obj_encoding(obj); +} + +static VALUE encoding_spec_rb_enc_get_index(VALUE self, VALUE obj) { + return INT2NUM(rb_enc_get_index(obj)); +} + +static VALUE encoding_spec_rb_enc_set_index(VALUE self, VALUE obj, VALUE index) { + int i = NUM2INT(index); + + rb_encoding* enc = rb_enc_from_index(i); + rb_enc_set_index(obj, i); + + return rb_ary_new3(2, rb_str_new2(rb_enc_name(enc)), + rb_str_new2(rb_enc_name(rb_enc_get(obj)))); +} + +static VALUE encoding_spec_rb_enc_str_coderange(VALUE self, VALUE str) { + int coderange = rb_enc_str_coderange(str); + + switch(coderange) { + case ENC_CODERANGE_UNKNOWN: + return ID2SYM(rb_intern("coderange_unknown")); + case ENC_CODERANGE_7BIT: + return ID2SYM(rb_intern("coderange_7bit")); + case ENC_CODERANGE_VALID: + return ID2SYM(rb_intern("coderange_valid")); + case ENC_CODERANGE_BROKEN: + return ID2SYM(rb_intern("coderange_broken")); + default: + return ID2SYM(rb_intern("coderange_unrecognized")); + } +} + +static VALUE encoding_spec_rb_enc_str_new_cstr(VALUE self, VALUE str, VALUE enc) { + rb_encoding *e = rb_to_encoding(enc); + return rb_enc_str_new_cstr(StringValueCStr(str), e); +} + +static VALUE encoding_spec_rb_enc_str_new_cstr_constant(VALUE self, VALUE enc) { + if (NIL_P(enc)) { + rb_encoding *e = NULL; + return rb_enc_str_new_static("test string literal", strlen("test string literal"), e); + } else { + rb_encoding *e = rb_to_encoding(enc); + return rb_enc_str_new_cstr("test string literal", e); + } +} + +static VALUE encoding_spec_rb_enc_str_new(VALUE self, VALUE str, VALUE len, VALUE enc) { + return rb_enc_str_new(RSTRING_PTR(str), FIX2INT(len), rb_to_encoding(enc)); +} + +static VALUE encoding_spec_ENCODING_GET(VALUE self, VALUE obj) { + return INT2NUM(ENCODING_GET(obj)); +} + +static VALUE encoding_spec_ENCODING_SET(VALUE self, VALUE obj, VALUE index) { + int i = NUM2INT(index); + + rb_encoding* enc = rb_enc_from_index(i); + ENCODING_SET(obj, i); + + return rb_ary_new3(2, rb_str_new2(rb_enc_name(enc)), + rb_str_new2(rb_enc_name(rb_enc_get(obj)))); +} + +static VALUE encoding_spec_rb_enc_to_index(VALUE self, VALUE name) { + return INT2NUM(rb_enc_to_index(NIL_P(name) ? NULL : rb_enc_find(RSTRING_PTR(name)))); +} + +static VALUE encoding_spec_rb_to_encoding(VALUE self, VALUE obj) { + return rb_str_new2(rb_to_encoding(obj)->name); +} + +static rb_encoding** native_rb_encoding_pointer; + +static VALUE encoding_spec_rb_to_encoding_native_store(VALUE self, VALUE obj) { + rb_encoding* enc = rb_to_encoding(obj); + VALUE address = SIZET2NUM((size_t) native_rb_encoding_pointer); + *native_rb_encoding_pointer = enc; + return address; +} + +static VALUE encoding_spec_rb_to_encoding_native_name(VALUE self, VALUE address) { + rb_encoding** ptr = (rb_encoding**) NUM2SIZET(address); + rb_encoding* enc = *ptr; + return rb_str_new2(enc->name); +} + +static VALUE encoding_spec_rb_to_encoding_index(VALUE self, VALUE obj) { + return INT2NUM(rb_to_encoding_index(obj)); +} + +static VALUE encoding_spec_rb_enc_nth(VALUE self, VALUE str, VALUE index) { + char* start = RSTRING_PTR(str); + char* end = start + RSTRING_LEN(str); + char* ptr = rb_enc_nth(start, end, FIX2LONG(index), rb_enc_get(str)); + return LONG2NUM(ptr - start); +} + +static VALUE encoding_spec_rb_enc_codepoint_len(VALUE self, VALUE str) { + char* start = RSTRING_PTR(str); + char* end = start + RSTRING_LEN(str); + + int len; + unsigned int codepoint = rb_enc_codepoint_len(start, end, &len, rb_enc_get(str)); + + return rb_ary_new3(2, LONG2NUM(codepoint), LONG2NUM(len)); +} + +static VALUE encoding_spec_rb_enc_str_asciionly_p(VALUE self, VALUE str) { + if (rb_enc_str_asciionly_p(str)) { + return Qtrue; + } else { + return Qfalse; + } +} + +static VALUE encoding_spec_rb_enc_raise(VALUE self, VALUE encoding, VALUE exception_class, VALUE format) { + rb_encoding *e = rb_to_encoding(encoding); + const char *f = RSTRING_PTR(format); + + rb_enc_raise(e, exception_class, "%s", f); +} + +static VALUE encoding_spec_rb_uv_to_utf8(VALUE self, VALUE buf, VALUE num) { + int len = rb_uv_to_utf8(RSTRING_PTR(buf), NUM2INT(num)); + RB_ENC_CODERANGE_CLEAR(buf); + return INT2NUM(len); +} + +static VALUE encoding_spec_ONIGENC_MBC_CASE_FOLD(VALUE self, VALUE str) { + char *beg = RSTRING_PTR(str); + char *beg_initial = beg; + char *end = beg + 2; + OnigUChar fold[ONIGENC_GET_CASE_FOLD_CODES_MAX_NUM]; + memset(fold, '\1', sizeof(fold)); + rb_encoding *enc = rb_enc_get(str); + int r = ONIGENC_MBC_CASE_FOLD(enc, ONIGENC_CASE_FOLD, &beg, (const OnigUChar *)end, fold); + if (r > 0 && fold[r] != '\1') { + rb_raise(rb_eRuntimeError, "should not change bytes after len"); + } + VALUE str_result = r <= 0 ? Qnil : rb_enc_str_new((char *)fold, r, enc); + long bytes_used = beg - beg_initial; + return rb_ary_new3(2, str_result, INT2FIX(bytes_used)); +} + +static VALUE encoding_spec_rb_enc_codelen(VALUE self, VALUE code, VALUE encoding) { + unsigned int c = FIX2UINT(code); + rb_encoding *enc = rb_to_encoding(encoding); + return INT2FIX(rb_enc_codelen(c, enc)); +} + +static VALUE encoding_spec_rb_enc_strlen(VALUE self, VALUE str, VALUE length, VALUE encoding) { + int l = FIX2INT(length); + char *p = RSTRING_PTR(str); + char *e = p + l; + + return LONG2FIX(rb_enc_strlen(p, e, rb_to_encoding(encoding))); +} + +static VALUE encoding_spec_rb_enc_left_char_head(VALUE self, VALUE str, VALUE offset) { + char *ptr = RSTRING_PTR(str); + char *result = rb_enc_left_char_head(ptr, ptr + NUM2INT(offset), RSTRING_END(str), rb_enc_get(str)); + return LONG2NUM(result - ptr); +} + +static VALUE encoding_spec_rb_define_dummy_encoding(VALUE self, VALUE name) { + return INT2NUM(rb_define_dummy_encoding(RSTRING_PTR(name))); +} + +void Init_encoding_spec(void) { + VALUE cls; + native_rb_encoding_pointer = (rb_encoding**) malloc(sizeof(rb_encoding*)); + + cls = rb_define_class("CApiEncodingSpecs", rb_cObject); + rb_define_method(cls, "ENC_CODERANGE_ASCIIONLY", + encoding_spec_ENC_CODERANGE_ASCIIONLY, 1); + + rb_define_method(cls, "rb_usascii_encoding", encoding_spec_rb_usascii_encoding, 0); + rb_define_method(cls, "rb_usascii_encindex", encoding_spec_rb_usascii_encindex, 0); + rb_define_method(cls, "rb_ascii8bit_encoding", encoding_spec_rb_ascii8bit_encoding, 0); + rb_define_method(cls, "rb_ascii8bit_encindex", encoding_spec_rb_ascii8bit_encindex, 0); + rb_define_method(cls, "rb_utf8_encoding", encoding_spec_rb_utf8_encoding, 0); + rb_define_method(cls, "rb_utf8_encindex", encoding_spec_rb_utf8_encindex, 0); + rb_define_method(cls, "rb_locale_encoding", encoding_spec_rb_locale_encoding, 0); + rb_define_method(cls, "rb_locale_encindex", encoding_spec_rb_locale_encindex, 0); + rb_define_method(cls, "rb_filesystem_encoding", encoding_spec_rb_filesystem_encoding, 0); + rb_define_method(cls, "rb_filesystem_encindex", encoding_spec_rb_filesystem_encindex, 0); + rb_define_method(cls, "rb_default_internal_encoding", encoding_spec_rb_default_internal_encoding, 0); + rb_define_method(cls, "rb_default_external_encoding", encoding_spec_rb_default_external_encoding, 0); + rb_define_method(cls, "rb_enc_alias", encoding_spec_rb_enc_alias, 2); + rb_define_method(cls, "MBCLEN_CHARFOUND_P", encoding_spec_MBCLEN_CHARFOUND_P, 1); + rb_define_method(cls, "rb_enc_associate", encoding_spec_rb_enc_associate, 2); + rb_define_method(cls, "rb_enc_associate_index", encoding_spec_rb_enc_associate_index, 2); + rb_define_method(cls, "rb_enc_compatible", encoding_spec_rb_enc_compatible, 2); + rb_define_method(cls, "rb_enc_copy", encoding_spec_rb_enc_copy, 2); + rb_define_method(cls, "rb_enc_codelen", encoding_spec_rb_enc_codelen, 2); + rb_define_method(cls, "rb_enc_strlen", encoding_spec_rb_enc_strlen, 3); + rb_define_method(cls, "rb_enc_find", encoding_spec_rb_enc_find, 1); + rb_define_method(cls, "rb_enc_find_index", encoding_spec_rb_enc_find_index, 1); + rb_define_method(cls, "rb_enc_isalnum", encoding_spec_rb_enc_isalnum, 2); + rb_define_method(cls, "rb_enc_isspace", encoding_spec_rb_enc_isspace, 2); + rb_define_method(cls, "rb_enc_from_index", encoding_spec_rb_enc_from_index, 1); + rb_define_method(cls, "rb_enc_mbc_to_codepoint", encoding_spec_rb_enc_mbc_to_codepoint, 1); + rb_define_method(cls, "rb_enc_mbcput", encoding_spec_rb_enc_mbcput, 2); + rb_define_method(cls, "rb_enc_from_encoding", encoding_spec_rb_enc_from_encoding, 1); + rb_define_method(cls, "rb_enc_get", encoding_spec_rb_enc_get, 1); + rb_define_method(cls, "rb_enc_precise_mbclen", encoding_spec_rb_enc_precise_mbclen, 2); + rb_define_method(cls, "rb_obj_encoding", encoding_spec_rb_obj_encoding, 1); + rb_define_method(cls, "rb_enc_get_index", encoding_spec_rb_enc_get_index, 1); + rb_define_method(cls, "rb_enc_set_index", encoding_spec_rb_enc_set_index, 2); + rb_define_method(cls, "rb_enc_str_coderange", encoding_spec_rb_enc_str_coderange, 1); + rb_define_method(cls, "rb_enc_str_new_cstr", encoding_spec_rb_enc_str_new_cstr, 2); + rb_define_method(cls, "rb_enc_str_new_cstr_constant", encoding_spec_rb_enc_str_new_cstr_constant, 1); + rb_define_method(cls, "rb_enc_str_new", encoding_spec_rb_enc_str_new, 3); + rb_define_method(cls, "ENCODING_GET", encoding_spec_ENCODING_GET, 1); + rb_define_method(cls, "ENCODING_SET", encoding_spec_ENCODING_SET, 2); + rb_define_method(cls, "rb_enc_to_index", encoding_spec_rb_enc_to_index, 1); + rb_define_method(cls, "rb_to_encoding", encoding_spec_rb_to_encoding, 1); + rb_define_method(cls, "rb_to_encoding_native_store", encoding_spec_rb_to_encoding_native_store, 1); + rb_define_method(cls, "rb_to_encoding_native_name", encoding_spec_rb_to_encoding_native_name, 1); + rb_define_method(cls, "rb_to_encoding_index", encoding_spec_rb_to_encoding_index, 1); + rb_define_method(cls, "rb_enc_nth", encoding_spec_rb_enc_nth, 2); + rb_define_method(cls, "rb_enc_codepoint_len", encoding_spec_rb_enc_codepoint_len, 1); + rb_define_method(cls, "rb_enc_str_asciionly_p", encoding_spec_rb_enc_str_asciionly_p, 1); + rb_define_method(cls, "rb_enc_raise", encoding_spec_rb_enc_raise, 3); + rb_define_method(cls, "rb_uv_to_utf8", encoding_spec_rb_uv_to_utf8, 2); + rb_define_method(cls, "ONIGENC_MBC_CASE_FOLD", encoding_spec_ONIGENC_MBC_CASE_FOLD, 1); + rb_define_method(cls, "rb_enc_left_char_head", encoding_spec_rb_enc_left_char_head, 2); + rb_define_method(cls, "rb_define_dummy_encoding", encoding_spec_rb_define_dummy_encoding, 1); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/enumerator_spec.c b/spec/ruby/optional/capi/ext/enumerator_spec.c new file mode 100644 index 0000000000..917621c003 --- /dev/null +++ b/spec/ruby/optional/capi/ext/enumerator_spec.c @@ -0,0 +1,32 @@ +#include "ruby.h" +#include "rubyspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +VALUE enumerator_spec_rb_enumeratorize(int argc, VALUE *argv, VALUE self) { + VALUE obj, meth, args; + rb_scan_args(argc, argv, "2*", &obj, &meth, &args); + return rb_enumeratorize(obj, meth, (int)RARRAY_LEN(args), RARRAY_PTR(args)); +} + +VALUE enumerator_spec_size_fn(VALUE obj, VALUE args, VALUE anEnum) { + return INT2NUM(7); +} + +VALUE enumerator_spec_rb_enumeratorize_with_size(int argc, VALUE *argv, VALUE self) { + VALUE obj, meth, args; + rb_scan_args(argc, argv, "2*", &obj, &meth, &args); + return rb_enumeratorize_with_size(obj, meth, (int)RARRAY_LEN(args), RARRAY_PTR(args), enumerator_spec_size_fn); +} + +void Init_enumerator_spec(void) { + VALUE cls = rb_define_class("CApiEnumeratorSpecs", rb_cObject); + rb_define_method(cls, "rb_enumeratorize", enumerator_spec_rb_enumeratorize, -1); + rb_define_method(cls, "rb_enumeratorize_with_size", enumerator_spec_rb_enumeratorize_with_size, -1); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/exception_spec.c b/spec/ruby/optional/capi/ext/exception_spec.c new file mode 100644 index 0000000000..c3b94d7bcd --- /dev/null +++ b/spec/ruby/optional/capi/ext/exception_spec.c @@ -0,0 +1,84 @@ +#include "ruby.h" +#include "rubyspec.h" + +#include <stdio.h> +#include <string.h> + +#ifdef __cplusplus +extern "C" { +#endif + +VALUE exception_spec_rb_errinfo(VALUE self) { + return rb_errinfo(); +} + +VALUE exception_spec_rb_exc_new(VALUE self, VALUE str) { + char *cstr = StringValuePtr(str); + return rb_exc_new(rb_eException, cstr, strlen(cstr)); +} + +VALUE exception_spec_rb_exc_new2(VALUE self, VALUE str) { + char *cstr = StringValuePtr(str); + return rb_exc_new2(rb_eException, cstr); +} + +VALUE exception_spec_rb_exc_new3(VALUE self, VALUE str) { + return rb_exc_new3(rb_eException, str); +} + +VALUE exception_spec_rb_exc_raise(VALUE self, VALUE exc) { + if (self != Qundef) rb_exc_raise(exc); + return Qnil; +} + +VALUE exception_spec_rb_set_errinfo(VALUE self, VALUE exc) { + rb_set_errinfo(exc); + return Qnil; +} + +NORETURN(VALUE exception_spec_rb_error_frozen_object(VALUE self, VALUE object)); + +VALUE exception_spec_rb_error_frozen_object(VALUE self, VALUE object) { + rb_error_frozen_object(object); + UNREACHABLE_RETURN(Qnil); +} + +VALUE exception_spec_rb_syserr_new(VALUE self, VALUE num, VALUE msg) { + int n = NUM2INT(num); + char *cstr = NULL; + + if (msg != Qnil) { + cstr = StringValuePtr(msg); + } + + return rb_syserr_new(n, cstr); +} + +VALUE exception_spec_rb_syserr_new_str(VALUE self, VALUE num, VALUE msg) { + int n = NUM2INT(num); + return rb_syserr_new_str(n, msg); +} + +VALUE exception_spec_rb_make_exception(VALUE self, VALUE ary) { + int argc = RARRAY_LENINT(ary); + VALUE *argv = RARRAY_PTR(ary); + return rb_make_exception(argc, argv); +} + +void Init_exception_spec(void) { + VALUE cls = rb_define_class("CApiExceptionSpecs", rb_cObject); + rb_define_method(cls, "rb_errinfo", exception_spec_rb_errinfo, 0); + rb_define_method(cls, "rb_exc_new", exception_spec_rb_exc_new, 1); + rb_define_method(cls, "rb_exc_new2", exception_spec_rb_exc_new2, 1); + rb_define_method(cls, "rb_exc_new3", exception_spec_rb_exc_new3, 1); + rb_define_method(cls, "rb_exc_raise", exception_spec_rb_exc_raise, 1); + rb_define_method(cls, "rb_set_errinfo", exception_spec_rb_set_errinfo, 1); + rb_define_method(cls, "rb_error_frozen_object", exception_spec_rb_error_frozen_object, 1); + rb_define_method(cls, "rb_syserr_new", exception_spec_rb_syserr_new, 2); + rb_define_method(cls, "rb_syserr_new_str", exception_spec_rb_syserr_new_str, 2); + rb_define_method(cls, "rb_make_exception", exception_spec_rb_make_exception, 1); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/fiber_spec.c b/spec/ruby/optional/capi/ext/fiber_spec.c new file mode 100644 index 0000000000..db54f7ad8c --- /dev/null +++ b/spec/ruby/optional/capi/ext/fiber_spec.c @@ -0,0 +1,64 @@ +#include "ruby.h" +#include "rubyspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +VALUE fiber_spec_rb_fiber_current(VALUE self) { + return rb_fiber_current(); +} + +VALUE fiber_spec_rb_fiber_alive_p(VALUE self, VALUE fiber) { + return rb_fiber_alive_p(fiber); +} + +VALUE fiber_spec_rb_fiber_resume(VALUE self, VALUE fiber, VALUE ary) { + long argc = RARRAY_LEN(ary); + VALUE *argv = (VALUE*) alloca(sizeof(VALUE) * argc); + int i; + + for (i = 0; i < argc; i++) { + argv[i] = rb_ary_entry(ary, i); + } + + return rb_fiber_resume(fiber, (int)argc, argv); +} + +VALUE fiber_spec_rb_fiber_yield(VALUE self, VALUE ary) { + long argc = RARRAY_LEN(ary); + VALUE *argv = (VALUE*) alloca(sizeof(VALUE) * argc); + int i; + + for (i = 0; i < argc; i++) { + argv[i] = rb_ary_entry(ary, i); + } + return rb_fiber_yield((int)argc, argv); +} + +VALUE fiber_spec_rb_fiber_new_function(RB_BLOCK_CALL_FUNC_ARGLIST(args, dummy)) { + return rb_funcall(args, rb_intern("inspect"), 0); +} + +VALUE fiber_spec_rb_fiber_new(VALUE self) { + return rb_fiber_new(fiber_spec_rb_fiber_new_function, Qnil); +} + +VALUE fiber_spec_rb_fiber_raise(int argc, VALUE *argv, VALUE self) { + VALUE fiber = argv[0]; + return rb_fiber_raise(fiber, argc-1, argv+1); +} + +void Init_fiber_spec(void) { + VALUE cls = rb_define_class("CApiFiberSpecs", rb_cObject); + rb_define_method(cls, "rb_fiber_current", fiber_spec_rb_fiber_current, 0); + rb_define_method(cls, "rb_fiber_alive_p", fiber_spec_rb_fiber_alive_p, 1); + rb_define_method(cls, "rb_fiber_resume", fiber_spec_rb_fiber_resume, 2); + rb_define_method(cls, "rb_fiber_yield", fiber_spec_rb_fiber_yield, 1); + rb_define_method(cls, "rb_fiber_new", fiber_spec_rb_fiber_new, 0); + rb_define_method(cls, "rb_fiber_raise", fiber_spec_rb_fiber_raise, -1); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/file_spec.c b/spec/ruby/optional/capi/ext/file_spec.c new file mode 100644 index 0000000000..cd4a653765 --- /dev/null +++ b/spec/ruby/optional/capi/ext/file_spec.c @@ -0,0 +1,29 @@ +#include "ruby.h" +#include "rubyspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +VALUE file_spec_rb_file_open(VALUE self, VALUE name, VALUE mode) { + return rb_file_open(RSTRING_PTR(name), RSTRING_PTR(mode)); +} + +VALUE file_spec_rb_file_open_str(VALUE self, VALUE name, VALUE mode) { + return rb_file_open_str(name, RSTRING_PTR(mode)); +} + +VALUE file_spec_FilePathValue(VALUE self, VALUE obj) { + return FilePathValue(obj); +} + +void Init_file_spec(void) { + VALUE cls = rb_define_class("CApiFileSpecs", rb_cObject); + rb_define_method(cls, "rb_file_open", file_spec_rb_file_open, 2); + rb_define_method(cls, "rb_file_open_str", file_spec_rb_file_open_str, 2); + rb_define_method(cls, "FilePathValue", file_spec_FilePathValue, 1); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/finalizer_spec.c b/spec/ruby/optional/capi/ext/finalizer_spec.c new file mode 100644 index 0000000000..83347da912 --- /dev/null +++ b/spec/ruby/optional/capi/ext/finalizer_spec.c @@ -0,0 +1,25 @@ +#include "ruby.h" +#include "rubyspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static VALUE define_finalizer(VALUE self, VALUE obj, VALUE finalizer) { + return rb_define_finalizer(obj, finalizer); +} + +static VALUE undefine_finalizer(VALUE self, VALUE obj) { + return rb_undefine_finalizer(obj); +} + +void Init_finalizer_spec(void) { + VALUE cls = rb_define_class("CApiFinalizerSpecs", rb_cObject); + + rb_define_method(cls, "rb_define_finalizer", define_finalizer, 2); + rb_define_method(cls, "rb_undefine_finalizer", undefine_finalizer, 1); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/fixnum_spec.c b/spec/ruby/optional/capi/ext/fixnum_spec.c new file mode 100644 index 0000000000..7048ce3f13 --- /dev/null +++ b/spec/ruby/optional/capi/ext/fixnum_spec.c @@ -0,0 +1,26 @@ +#include "ruby.h" +#include "rubyspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static VALUE fixnum_spec_FIX2INT(VALUE self, VALUE value) { + int i = FIX2INT(value); + return INT2NUM(i); +} + +static VALUE fixnum_spec_FIX2UINT(VALUE self, VALUE value) { + unsigned int i = FIX2UINT(value); + return UINT2NUM(i); +} + +void Init_fixnum_spec(void) { + VALUE cls = rb_define_class("CApiFixnumSpecs", rb_cObject); + rb_define_method(cls, "FIX2INT", fixnum_spec_FIX2INT, 1); + rb_define_method(cls, "FIX2UINT", fixnum_spec_FIX2UINT, 1); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/float_spec.c b/spec/ruby/optional/capi/ext/float_spec.c new file mode 100644 index 0000000000..3db05cef8c --- /dev/null +++ b/spec/ruby/optional/capi/ext/float_spec.c @@ -0,0 +1,47 @@ +#include "ruby.h" +#include "rubyspec.h" + +#include <math.h> + +#ifdef __cplusplus +extern "C" { +#endif + +static VALUE float_spec_new_zero(VALUE self) { + double flt = 0; + return rb_float_new(flt); +} + +static VALUE float_spec_new_point_five(VALUE self) { + double flt = 0.555; + return rb_float_new(flt); +} + +static VALUE float_spec_rb_Float(VALUE self, VALUE float_str) { + return rb_Float(float_str); +} + +static VALUE float_spec_RFLOAT_VALUE(VALUE self, VALUE float_h) { + return rb_float_new(RFLOAT_VALUE(float_h)); +} + +static VALUE float_spec_RB_FLOAT_TYPE_P(VALUE self, VALUE val) { + if (RB_FLOAT_TYPE_P(val)) { + return Qtrue; + } else { + return Qfalse; + } +} + +void Init_float_spec(void) { + VALUE cls = rb_define_class("CApiFloatSpecs", rb_cObject); + rb_define_method(cls, "new_zero", float_spec_new_zero, 0); + rb_define_method(cls, "new_point_five", float_spec_new_point_five, 0); + rb_define_method(cls, "rb_Float", float_spec_rb_Float, 1); + rb_define_method(cls, "RFLOAT_VALUE", float_spec_RFLOAT_VALUE, 1); + rb_define_method(cls, "RB_FLOAT_TYPE_P", float_spec_RB_FLOAT_TYPE_P, 1); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/gc_spec.c b/spec/ruby/optional/capi/ext/gc_spec.c new file mode 100644 index 0000000000..2637ad27ac --- /dev/null +++ b/spec/ruby/optional/capi/ext/gc_spec.c @@ -0,0 +1,149 @@ +#include "ruby.h" +#include "rubyspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +VALUE registered_tagged_value; +VALUE registered_reference_value; +VALUE registered_before_rb_gc_register_address; +VALUE registered_before_rb_global_variable_string; +VALUE registered_before_rb_global_variable_bignum; +VALUE registered_before_rb_global_variable_float; +VALUE registered_after_rb_global_variable_string; +VALUE registered_after_rb_global_variable_bignum; +VALUE registered_after_rb_global_variable_float; +VALUE rb_gc_register_address_outside_init; + +VALUE rb_gc_register_mark_object_not_referenced_float; + +static VALUE registered_tagged_address(VALUE self) { + return registered_tagged_value; +} + +static VALUE registered_reference_address(VALUE self) { + return registered_reference_value; +} + +static VALUE get_registered_before_rb_gc_register_address(VALUE self) { + return registered_before_rb_gc_register_address; +} + +static VALUE get_registered_before_rb_global_variable_string(VALUE self) { + return registered_before_rb_global_variable_string; +} + +static VALUE get_registered_before_rb_global_variable_bignum(VALUE self) { + return registered_before_rb_global_variable_bignum; +} + +static VALUE get_registered_before_rb_global_variable_float(VALUE self) { + return registered_before_rb_global_variable_float; +} + +static VALUE get_registered_after_rb_global_variable_string(VALUE self) { + return registered_after_rb_global_variable_string; +} + +static VALUE get_registered_after_rb_global_variable_bignum(VALUE self) { + return registered_after_rb_global_variable_bignum; +} + +static VALUE get_registered_after_rb_global_variable_float(VALUE self) { + return registered_after_rb_global_variable_float; +} + +static VALUE gc_spec_rb_gc_register_address(VALUE self) { + rb_gc_register_address(&rb_gc_register_address_outside_init); + rb_gc_register_address_outside_init = rb_str_new_cstr("rb_gc_register_address() outside Init_"); + return rb_gc_register_address_outside_init; +} + +static VALUE gc_spec_rb_gc_unregister_address(VALUE self) { + rb_gc_unregister_address(&rb_gc_register_address_outside_init); + return Qnil; +} + +static VALUE gc_spec_rb_gc_enable(VALUE self) { + return rb_gc_enable(); +} + +static VALUE gc_spec_rb_gc_disable(VALUE self) { + return rb_gc_disable(); +} + +static VALUE gc_spec_rb_gc(VALUE self) { + rb_gc(); + return Qnil; +} + +static VALUE gc_spec_rb_gc_latest_gc_info(VALUE self, VALUE hash_or_key) { + return rb_gc_latest_gc_info(hash_or_key); +} + +static VALUE gc_spec_rb_gc_adjust_memory_usage(VALUE self, VALUE diff) { + rb_gc_adjust_memory_usage(NUM2SSIZET(diff)); + return Qnil; +} + +static VALUE gc_spec_rb_gc_register_mark_object(VALUE self, VALUE obj) { + rb_gc_register_mark_object(obj); + return Qnil; +} + +static VALUE gc_spec_rb_gc_register_mark_object_not_referenced_float(VALUE self) { + return rb_gc_register_mark_object_not_referenced_float; +} + +void Init_gc_spec(void) { + VALUE cls = rb_define_class("CApiGCSpecs", rb_cObject); + + rb_gc_register_address(®istered_tagged_value); + rb_gc_register_address(®istered_reference_value); + rb_gc_register_address(®istered_before_rb_gc_register_address); + rb_global_variable(®istered_before_rb_global_variable_string); + rb_global_variable(®istered_before_rb_global_variable_bignum); + rb_global_variable(®istered_before_rb_global_variable_float); + + registered_tagged_value = INT2NUM(10); + registered_reference_value = rb_str_new2("Globally registered data"); + registered_before_rb_gc_register_address = rb_str_new_cstr("registered before rb_gc_register_address()"); + + registered_before_rb_global_variable_string = rb_str_new_cstr("registered before rb_global_variable()"); + registered_before_rb_global_variable_bignum = LL2NUM(INT64_MAX); + registered_before_rb_global_variable_float = DBL2NUM(3.14); + + registered_after_rb_global_variable_string = rb_str_new_cstr("registered after rb_global_variable()"); + rb_global_variable(®istered_after_rb_global_variable_string); + registered_after_rb_global_variable_bignum = LL2NUM(INT64_MAX); + rb_global_variable(®istered_after_rb_global_variable_bignum); + registered_after_rb_global_variable_float = DBL2NUM(6.28); + rb_global_variable(®istered_after_rb_global_variable_float); + + rb_gc_register_mark_object_not_referenced_float = DBL2NUM(1.61); + rb_gc_register_mark_object(rb_gc_register_mark_object_not_referenced_float); + + rb_define_method(cls, "registered_tagged_address", registered_tagged_address, 0); + rb_define_method(cls, "registered_reference_address", registered_reference_address, 0); + rb_define_method(cls, "registered_before_rb_gc_register_address", get_registered_before_rb_gc_register_address, 0); + rb_define_method(cls, "registered_before_rb_global_variable_string", get_registered_before_rb_global_variable_string, 0); + rb_define_method(cls, "registered_before_rb_global_variable_bignum", get_registered_before_rb_global_variable_bignum, 0); + rb_define_method(cls, "registered_before_rb_global_variable_float", get_registered_before_rb_global_variable_float, 0); + rb_define_method(cls, "registered_after_rb_global_variable_string", get_registered_after_rb_global_variable_string, 0); + rb_define_method(cls, "registered_after_rb_global_variable_bignum", get_registered_after_rb_global_variable_bignum, 0); + rb_define_method(cls, "registered_after_rb_global_variable_float", get_registered_after_rb_global_variable_float, 0); + rb_define_method(cls, "rb_gc_register_address", gc_spec_rb_gc_register_address, 0); + rb_define_method(cls, "rb_gc_unregister_address", gc_spec_rb_gc_unregister_address, 0); + rb_define_method(cls, "rb_gc_enable", gc_spec_rb_gc_enable, 0); + rb_define_method(cls, "rb_gc_disable", gc_spec_rb_gc_disable, 0); + rb_define_method(cls, "rb_gc", gc_spec_rb_gc, 0); + rb_define_method(cls, "rb_gc_adjust_memory_usage", gc_spec_rb_gc_adjust_memory_usage, 1); + rb_define_method(cls, "rb_gc_register_mark_object", gc_spec_rb_gc_register_mark_object, 1); + rb_define_method(cls, "rb_gc_register_mark_object_not_referenced_float", gc_spec_rb_gc_register_mark_object_not_referenced_float, 0); + rb_define_method(cls, "rb_gc_latest_gc_info", gc_spec_rb_gc_latest_gc_info, 1); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/globals_spec.c b/spec/ruby/optional/capi/ext/globals_spec.c new file mode 100644 index 0000000000..20dea1a05a --- /dev/null +++ b/spec/ruby/optional/capi/ext/globals_spec.c @@ -0,0 +1,161 @@ +#include "ruby.h" +#include "rubyspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +VALUE g_hooked_var; + +VALUE var_2x_getter(ID id, VALUE *data) { + return *data; +} + +void var_2x_setter(VALUE val, ID id, VALUE *var) { + *var = INT2NUM(NUM2INT(val) * 2); +} + +static VALUE sb_define_hooked_variable(VALUE self, VALUE var_name) { + rb_define_hooked_variable(StringValuePtr(var_name), &g_hooked_var, var_2x_getter, var_2x_setter); + return Qnil; +} + +static VALUE sb_define_hooked_variable_default_accessors(VALUE self, VALUE var_name) { + rb_define_hooked_variable(StringValuePtr(var_name), &g_hooked_var, (rb_gvar_getter_t*) NULL, (rb_gvar_setter_t*) NULL); + return Qnil; +} + +static VALUE sb_define_hooked_variable_null_var(VALUE self, VALUE var_name) { + rb_define_hooked_variable(StringValuePtr(var_name), NULL, (rb_gvar_getter_t*) NULL, (rb_gvar_setter_t*) NULL); + return Qnil; +} + +VALUE g_ro_var; + +static VALUE sb_define_readonly_variable(VALUE self, VALUE var_name, VALUE val) { + g_ro_var = val; + rb_define_readonly_variable(StringValuePtr(var_name), &g_ro_var); + return Qnil; +} + +VALUE g_var; + +static VALUE sb_get_global_value(VALUE self) { + return g_var; +} + +static VALUE sb_define_variable(VALUE self, VALUE var_name, VALUE val) { + g_var = val; + rb_define_variable(StringValuePtr(var_name), &g_var); + return Qnil; +} + +long virtual_var_storage; + +VALUE incrementing_getter(ID id, VALUE *data) { + return LONG2FIX(virtual_var_storage++); +} + +void incrementing_setter(VALUE val, ID id, VALUE *data) { + virtual_var_storage = FIX2LONG(val); +} + +static VALUE sb_define_virtual_variable_default_accessors(VALUE self, VALUE name) { + rb_define_virtual_variable(StringValuePtr(name), (rb_gvar_getter_t*) NULL, (rb_gvar_setter_t*) NULL); + return Qnil; +} + +static VALUE sb_define_virtual_variable_incrementing_accessors(VALUE self, VALUE name) { + rb_define_virtual_variable(StringValuePtr(name), incrementing_getter, incrementing_setter); + return Qnil; +} + +static VALUE sb_f_global_variables(VALUE self) { + return rb_f_global_variables(); +} + +static VALUE sb_gv_get(VALUE self, VALUE var) { + return rb_gv_get(StringValuePtr(var)); +} + +static VALUE sb_gv_set(VALUE self, VALUE var, VALUE val) { + return rb_gv_set(StringValuePtr(var), val); +} + +static VALUE global_spec_rb_stdin(VALUE self) { + return rb_stdin; +} + +static VALUE global_spec_rb_stdout(VALUE self) { + return rb_stdout; +} + +static VALUE global_spec_rb_stderr(VALUE self) { + return rb_stderr; +} + +static VALUE global_spec_rb_defout(VALUE self) { + return rb_defout; +} + +static VALUE global_spec_rb_fs(VALUE self) { + return rb_fs; +} + +static VALUE global_spec_rb_rs(VALUE self) { + return rb_rs; +} + +static VALUE global_spec_rb_default_rs(VALUE self) { + return rb_default_rs; +} + +static VALUE global_spec_rb_output_rs(VALUE self) { + return rb_output_rs; +} + +static VALUE global_spec_rb_output_fs(VALUE self) { + return rb_output_fs; +} + +static VALUE global_spec_rb_lastline_set(VALUE self, VALUE line) { + rb_lastline_set(line); + return Qnil; +} + +static VALUE global_spec_rb_lastline_get(VALUE self) { + return rb_lastline_get(); +} + +void Init_globals_spec(void) { + VALUE cls = rb_define_class("CApiGlobalSpecs", rb_cObject); + g_hooked_var = Qnil; + rb_define_method(cls, "rb_define_hooked_variable_2x", sb_define_hooked_variable, 1); + rb_define_method(cls, "rb_define_hooked_variable_default_accessors", sb_define_hooked_variable_default_accessors, 1); + rb_define_method(cls, "rb_define_hooked_variable_null_var", sb_define_hooked_variable_null_var, 1); + g_ro_var = Qnil; + rb_define_method(cls, "rb_define_readonly_variable", sb_define_readonly_variable, 2); + g_var = Qnil; + rb_define_method(cls, "rb_define_variable", sb_define_variable, 2); + rb_define_method(cls, "rb_define_virtual_variable_default_accessors", sb_define_virtual_variable_default_accessors, 1); + rb_define_method(cls, "rb_define_virtual_variable_incrementing_accessors", sb_define_virtual_variable_incrementing_accessors, 1); + rb_define_method(cls, "sb_get_global_value", sb_get_global_value, 0); + rb_define_method(cls, "rb_f_global_variables", sb_f_global_variables, 0); + rb_define_method(cls, "sb_gv_get", sb_gv_get, 1); + rb_define_method(cls, "sb_gv_set", sb_gv_set, 2); + rb_define_method(cls, "rb_stdin", global_spec_rb_stdin, 0); + rb_define_method(cls, "rb_stdout", global_spec_rb_stdout, 0); + rb_define_method(cls, "rb_stderr", global_spec_rb_stderr, 0); + rb_define_method(cls, "rb_defout", global_spec_rb_defout, 0); + rb_define_method(cls, "rb_fs", global_spec_rb_fs, 0); + rb_define_method(cls, "rb_rs", global_spec_rb_rs, 0); + rb_define_method(cls, "rb_default_rs", global_spec_rb_default_rs, 0); + rb_define_method(cls, "rb_output_rs", global_spec_rb_output_rs, 0); + rb_define_method(cls, "rb_output_fs", global_spec_rb_output_fs, 0); + rb_define_method(cls, "rb_lastline_set", global_spec_rb_lastline_set, 1); + rb_define_method(cls, "rb_lastline_get", global_spec_rb_lastline_get, 0); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/hash_spec.c b/spec/ruby/optional/capi/ext/hash_spec.c new file mode 100644 index 0000000000..653917f2c4 --- /dev/null +++ b/spec/ruby/optional/capi/ext/hash_spec.c @@ -0,0 +1,180 @@ +#include "ruby.h" +#include "rubyspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +VALUE hash_spec_rb_hash(VALUE self, VALUE hash) { + return rb_hash(hash); +} + +VALUE hash_spec_rb_Hash(VALUE self, VALUE val) { + return rb_Hash(val); +} + +VALUE hash_spec_rb_hash_dup(VALUE self, VALUE hash) { + return rb_hash_dup(hash); +} + +VALUE hash_spec_rb_hash_fetch(VALUE self, VALUE hash, VALUE key) { + return rb_hash_fetch(hash, key); +} + +VALUE hash_spec_rb_hash_freeze(VALUE self, VALUE hash) { + return rb_hash_freeze(hash); +} + +VALUE hash_spec_rb_hash_aref(VALUE self, VALUE hash, VALUE key) { + return rb_hash_aref(hash, key); +} + +VALUE hash_spec_rb_hash_aref_nil(VALUE self, VALUE hash, VALUE key) { + VALUE ret = rb_hash_aref(hash, key); + return NIL_P(ret) ? Qtrue : Qfalse; +} + +VALUE hash_spec_rb_hash_aset(VALUE self, VALUE hash, VALUE key, VALUE val) { + return rb_hash_aset(hash, key, val); +} + +VALUE hash_spec_rb_hash_clear(VALUE self, VALUE hash) { + return rb_hash_clear(hash); +} + +VALUE hash_spec_rb_hash_delete(VALUE self, VALUE hash, VALUE key) { + return rb_hash_delete(hash, key); +} + +VALUE hash_spec_rb_hash_delete_if(VALUE self, VALUE hash) { + return rb_hash_delete_if(hash); +} + +static int foreach_i(VALUE key, VALUE val, VALUE other) { + rb_hash_aset(other, key, val); + return 0; /* ST_CONTINUE; */ +} + +static int foreach_stop_i(VALUE key, VALUE val, VALUE other) { + rb_hash_aset(other, key, val); + return 1; /* ST_STOP; */ +} + +static int foreach_delete_i(VALUE key, VALUE val, VALUE other) { + rb_hash_aset(other, key, val); + return 2; /* ST_DELETE; */ +} + +VALUE hash_spec_rb_hash_foreach(VALUE self, VALUE hsh) { + VALUE other = rb_hash_new(); + rb_hash_foreach(hsh, foreach_i, other); + return other; +} + +VALUE hash_spec_rb_hash_foreach_stop(VALUE self, VALUE hsh) { + VALUE other = rb_hash_new(); + rb_hash_foreach(hsh, foreach_stop_i, other); + return other; +} + +VALUE hash_spec_rb_hash_foreach_delete(VALUE self, VALUE hsh) { + VALUE other = rb_hash_new(); + rb_hash_foreach(hsh, foreach_delete_i, other); + return other; +} + +VALUE hash_spec_rb_hash_lookup(VALUE self, VALUE hash, VALUE key) { + return rb_hash_lookup(hash, key); +} + +VALUE hash_spec_rb_hash_lookup_nil(VALUE self, VALUE hash, VALUE key) { + VALUE ret = rb_hash_lookup(hash, key); + return ret == Qnil ? Qtrue : Qfalse; +} + +VALUE hash_spec_rb_hash_lookup2(VALUE self, VALUE hash, VALUE key, VALUE def) { + return rb_hash_lookup2(hash, key, def); +} + +VALUE hash_spec_rb_hash_lookup2_default_undef(VALUE self, VALUE hash, VALUE key) { + VALUE ret = rb_hash_lookup2(hash, key, Qundef); + return ret == Qundef ? Qtrue : Qfalse; +} + +VALUE hash_spec_rb_hash_new(VALUE self) { + return rb_hash_new(); +} + +VALUE hash_spec_rb_hash_new_capa(VALUE self, VALUE capacity) { + return rb_hash_new_capa(NUM2LONG(capacity)); +} + +VALUE rb_ident_hash_new(void); /* internal.h, used in ripper */ + +VALUE hash_spec_rb_ident_hash_new(VALUE self) { + return rb_ident_hash_new(); +} + +VALUE hash_spec_rb_hash_size(VALUE self, VALUE hash) { + return rb_hash_size(hash); +} + +VALUE hash_spec_rb_hash_set_ifnone(VALUE self, VALUE hash, VALUE def) { + return rb_hash_set_ifnone(hash, def); +} + +VALUE hash_spec_compute_a_hash_code(VALUE self, VALUE seed) { + int int_seed = FIX2INT(seed); + st_index_t h = rb_hash_start(int_seed); + h = rb_hash_uint32(h, 540u); + h = rb_hash_uint32(h, 340u); + h = rb_hash_end(h); + return ULONG2NUM(h); +} + +VALUE hash_spec_rb_hash_bulk_insert(VALUE self, VALUE array_len, VALUE array, VALUE hash) { + VALUE* ptr; + + if (array == Qnil) { + ptr = NULL; + } else { + ptr = RARRAY_PTR(array); + } + + long len = FIX2LONG(array_len); + rb_hash_bulk_insert(len, ptr, hash); + return Qnil; +} + +void Init_hash_spec(void) { + VALUE cls = rb_define_class("CApiHashSpecs", rb_cObject); + rb_define_method(cls, "rb_hash", hash_spec_rb_hash, 1); + rb_define_method(cls, "rb_Hash", hash_spec_rb_Hash, 1); + rb_define_method(cls, "rb_hash_dup", hash_spec_rb_hash_dup, 1); + rb_define_method(cls, "rb_hash_freeze", hash_spec_rb_hash_freeze, 1); + rb_define_method(cls, "rb_hash_aref", hash_spec_rb_hash_aref, 2); + rb_define_method(cls, "rb_hash_aref_nil", hash_spec_rb_hash_aref_nil, 2); + rb_define_method(cls, "rb_hash_aset", hash_spec_rb_hash_aset, 3); + rb_define_method(cls, "rb_hash_clear", hash_spec_rb_hash_clear, 1); + rb_define_method(cls, "rb_hash_delete", hash_spec_rb_hash_delete, 2); + rb_define_method(cls, "rb_hash_delete_if", hash_spec_rb_hash_delete_if, 1); + rb_define_method(cls, "rb_hash_fetch", hash_spec_rb_hash_fetch, 2); + rb_define_method(cls, "rb_hash_foreach", hash_spec_rb_hash_foreach, 1); + rb_define_method(cls, "rb_hash_foreach_stop", hash_spec_rb_hash_foreach_stop, 1); + rb_define_method(cls, "rb_hash_foreach_delete", hash_spec_rb_hash_foreach_delete, 1); + rb_define_method(cls, "rb_hash_lookup_nil", hash_spec_rb_hash_lookup_nil, 2); + rb_define_method(cls, "rb_hash_lookup", hash_spec_rb_hash_lookup, 2); + rb_define_method(cls, "rb_hash_lookup2", hash_spec_rb_hash_lookup2, 3); + rb_define_method(cls, "rb_hash_lookup2_default_undef", hash_spec_rb_hash_lookup2_default_undef, 2); + rb_define_method(cls, "rb_hash_new", hash_spec_rb_hash_new, 0); + rb_define_method(cls, "rb_hash_new_capa", hash_spec_rb_hash_new_capa, 1); + rb_define_method(cls, "rb_ident_hash_new", hash_spec_rb_ident_hash_new, 0); + rb_define_method(cls, "rb_hash_size", hash_spec_rb_hash_size, 1); + rb_define_method(cls, "rb_hash_set_ifnone", hash_spec_rb_hash_set_ifnone, 2); + rb_define_method(cls, "compute_a_hash_code", hash_spec_compute_a_hash_code, 1); + rb_define_method(cls, "rb_hash_bulk_insert", hash_spec_rb_hash_bulk_insert, 3); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/integer_spec.c b/spec/ruby/optional/capi/ext/integer_spec.c new file mode 100644 index 0000000000..792fc0652a --- /dev/null +++ b/spec/ruby/optional/capi/ext/integer_spec.c @@ -0,0 +1,40 @@ +#include "ruby.h" +#include "rubyspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static VALUE integer_spec_rb_integer_pack(VALUE self, VALUE value, + VALUE words, VALUE numwords, VALUE wordsize, VALUE nails, VALUE flags) { + int result = rb_integer_pack(value, (void*)RSTRING_PTR(words), FIX2INT(numwords), + FIX2INT(wordsize), FIX2INT(nails), FIX2INT(flags)); + return INT2FIX(result); +} + +RUBY_EXTERN VALUE rb_int_positive_pow(long x, unsigned long y); /* internal.h, used in ripper */ + +static VALUE integer_spec_rb_int_positive_pow(VALUE self, VALUE a, VALUE b) { + return rb_int_positive_pow(FIX2INT(a), FIX2INT(b)); +} + +void Init_integer_spec(void) { + VALUE cls = rb_define_class("CApiIntegerSpecs", rb_cObject); + rb_define_const(cls, "MSWORD", INT2NUM(INTEGER_PACK_MSWORD_FIRST)); + rb_define_const(cls, "LSWORD", INT2NUM(INTEGER_PACK_LSWORD_FIRST)); + rb_define_const(cls, "MSBYTE", INT2NUM(INTEGER_PACK_MSBYTE_FIRST)); + rb_define_const(cls, "LSBYTE", INT2NUM(INTEGER_PACK_LSBYTE_FIRST)); + rb_define_const(cls, "NATIVE", INT2NUM(INTEGER_PACK_NATIVE_BYTE_ORDER)); + rb_define_const(cls, "PACK_2COMP", INT2NUM(INTEGER_PACK_2COMP)); + rb_define_const(cls, "LITTLE_ENDIAN", INT2NUM(INTEGER_PACK_LITTLE_ENDIAN)); + rb_define_const(cls, "BIG_ENDIAN", INT2NUM(INTEGER_PACK_BIG_ENDIAN)); + rb_define_const(cls, "FORCE_BIGNUM", INT2NUM(INTEGER_PACK_FORCE_BIGNUM)); + rb_define_const(cls, "NEGATIVE", INT2NUM(INTEGER_PACK_NEGATIVE)); + + rb_define_method(cls, "rb_integer_pack", integer_spec_rb_integer_pack, 6); + rb_define_method(cls, "rb_int_positive_pow", integer_spec_rb_int_positive_pow, 2); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/io_spec.c b/spec/ruby/optional/capi/ext/io_spec.c new file mode 100644 index 0000000000..f3ede15729 --- /dev/null +++ b/spec/ruby/optional/capi/ext/io_spec.c @@ -0,0 +1,412 @@ +#include "ruby.h" +#include "rubyspec.h" +#include "ruby/io.h" +#include <errno.h> +#include <fcntl.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +static int set_non_blocking(int fd) { +#if defined(O_NONBLOCK) && defined(F_GETFL) + int flags = fcntl(fd, F_GETFL, 0); + if (flags == -1) + flags = 0; + return fcntl(fd, F_SETFL, flags | O_NONBLOCK); +#elif defined(FIOBIO) + int flags = 1; + return ioctl(fd, FIOBIO, &flags); +#else +#define SET_NON_BLOCKING_FAILS_ALWAYS 1 + errno = ENOSYS; + return -1; +#endif +} + +static int io_spec_get_fd(VALUE io) { + return rb_io_descriptor(io); +} + +VALUE io_spec_GetOpenFile_fd(VALUE self, VALUE io) { + return INT2NUM(io_spec_get_fd(io)); +} + +VALUE io_spec_rb_io_addstr(VALUE self, VALUE io, VALUE str) { + return rb_io_addstr(io, str); +} + +VALUE io_spec_rb_io_printf(VALUE self, VALUE io, VALUE ary) { + long argc = RARRAY_LEN(ary); + VALUE *argv = (VALUE*) alloca(sizeof(VALUE) * argc); + int i; + + for (i = 0; i < argc; i++) { + argv[i] = rb_ary_entry(ary, i); + } + + return rb_io_printf((int)argc, argv, io); +} + +VALUE io_spec_rb_io_print(VALUE self, VALUE io, VALUE ary) { + long argc = RARRAY_LEN(ary); + VALUE *argv = (VALUE*) alloca(sizeof(VALUE) * argc); + int i; + + for (i = 0; i < argc; i++) { + argv[i] = rb_ary_entry(ary, i); + } + + return rb_io_print((int)argc, argv, io); +} + +VALUE io_spec_rb_io_puts(VALUE self, VALUE io, VALUE ary) { + long argc = RARRAY_LEN(ary); + VALUE *argv = (VALUE*) alloca(sizeof(VALUE) * argc); + int i; + + for (i = 0; i < argc; i++) { + argv[i] = rb_ary_entry(ary, i); + } + + return rb_io_puts((int)argc, argv, io); +} + +VALUE io_spec_rb_io_write(VALUE self, VALUE io, VALUE str) { + return rb_io_write(io, str); +} + +VALUE io_spec_rb_io_check_io(VALUE self, VALUE io) { + return rb_io_check_io(io); +} + +VALUE io_spec_rb_io_check_readable(VALUE self, VALUE io) { + rb_io_t* fp; + GetOpenFile(io, fp); + rb_io_check_readable(fp); + return Qnil; +} + +VALUE io_spec_rb_io_check_writable(VALUE self, VALUE io) { + rb_io_t* fp; + GetOpenFile(io, fp); + rb_io_check_writable(fp); + return Qnil; +} + +VALUE io_spec_rb_io_check_closed(VALUE self, VALUE io) { + rb_io_t* fp; + GetOpenFile(io, fp); + rb_io_check_closed(fp); + return Qnil; +} + +VALUE io_spec_rb_io_taint_check(VALUE self, VALUE io) { + /*rb_io_t* fp; + GetOpenFile(io, fp);*/ + rb_io_taint_check(io); + return io; +} + +#define RB_IO_WAIT_READABLE_BUF 13 + +#ifdef SET_NON_BLOCKING_FAILS_ALWAYS +NORETURN(VALUE io_spec_rb_io_wait_readable(VALUE self, VALUE io, VALUE read_p)); +#endif + +VALUE io_spec_rb_io_wait_readable(VALUE self, VALUE io, VALUE read_p) { + int fd = io_spec_get_fd(io); +#ifndef SET_NON_BLOCKING_FAILS_ALWAYS + char buf[RB_IO_WAIT_READABLE_BUF]; + int ret, saved_errno; +#endif + + if (set_non_blocking(fd) == -1) + rb_sys_fail("set_non_blocking failed"); + +#ifndef SET_NON_BLOCKING_FAILS_ALWAYS + if (RTEST(read_p)) { + if (read(fd, buf, RB_IO_WAIT_READABLE_BUF) != -1) { + return Qnil; + } + saved_errno = errno; + rb_ivar_set(self, rb_intern("@write_data"), Qtrue); + errno = saved_errno; + } + + ret = rb_io_maybe_wait_readable(errno, io, Qnil); + + if (RTEST(read_p)) { + ssize_t r = read(fd, buf, RB_IO_WAIT_READABLE_BUF); + if (r != RB_IO_WAIT_READABLE_BUF) { + perror("read"); + return SSIZET2NUM(r); + } + rb_ivar_set(self, rb_intern("@read_data"), + rb_str_new(buf, RB_IO_WAIT_READABLE_BUF)); + } + + return ret ? Qtrue : Qfalse; +#else + UNREACHABLE_RETURN(Qnil); +#endif +} + +VALUE io_spec_rb_io_wait_writable(VALUE self, VALUE io) { + int ret = rb_io_maybe_wait_writable(errno, io, Qnil); + return ret ? Qtrue : Qfalse; +} + +VALUE io_spec_rb_io_maybe_wait_writable(VALUE self, VALUE error, VALUE io, VALUE timeout) { + int ret = rb_io_maybe_wait_writable(NUM2INT(error), io, timeout); + return INT2NUM(ret); +} + +#ifdef SET_NON_BLOCKING_FAILS_ALWAYS +NORETURN(VALUE io_spec_rb_io_maybe_wait_readable(VALUE self, VALUE error, VALUE io, VALUE timeout, VALUE read_p)); +#endif + +VALUE io_spec_rb_io_maybe_wait_readable(VALUE self, VALUE error, VALUE io, VALUE timeout, VALUE read_p) { + int fd = io_spec_get_fd(io); +#ifndef SET_NON_BLOCKING_FAILS_ALWAYS + char buf[RB_IO_WAIT_READABLE_BUF]; + int ret, saved_errno; +#endif + + if (set_non_blocking(fd) == -1) + rb_sys_fail("set_non_blocking failed"); + +#ifndef SET_NON_BLOCKING_FAILS_ALWAYS + if (RTEST(read_p)) { + if (read(fd, buf, RB_IO_WAIT_READABLE_BUF) != -1) { + return Qnil; + } + saved_errno = errno; + rb_ivar_set(self, rb_intern("@write_data"), Qtrue); + errno = saved_errno; + } + + // main part + ret = rb_io_maybe_wait_readable(NUM2INT(error), io, timeout); + + if (RTEST(read_p)) { + ssize_t r = read(fd, buf, RB_IO_WAIT_READABLE_BUF); + if (r != RB_IO_WAIT_READABLE_BUF) { + perror("read"); + return SSIZET2NUM(r); + } + rb_ivar_set(self, rb_intern("@read_data"), + rb_str_new(buf, RB_IO_WAIT_READABLE_BUF)); + } + + return INT2NUM(ret); +#else + UNREACHABLE_RETURN(Qnil); +#endif +} + +VALUE io_spec_rb_io_maybe_wait(VALUE self, VALUE error, VALUE io, VALUE events, VALUE timeout) { + return rb_io_maybe_wait(NUM2INT(error), io, events, timeout); +} + +VALUE io_spec_rb_thread_wait_fd(VALUE self, VALUE io) { + rb_thread_wait_fd(io_spec_get_fd(io)); + return Qnil; +} + +VALUE io_spec_rb_wait_for_single_fd(VALUE self, VALUE io, VALUE events, VALUE secs, VALUE usecs) { + VALUE timeout = Qnil; + if (!NIL_P(secs)) { + timeout = rb_float_new((double)FIX2INT(secs) + (0.000001 * FIX2INT(usecs))); + } + VALUE result = rb_io_wait(io, events, timeout); + if (result == Qfalse) return INT2FIX(0); + else return result; +} + +VALUE io_spec_rb_thread_fd_writable(VALUE self, VALUE io) { + rb_thread_fd_writable(io_spec_get_fd(io)); + return Qnil; +} + +VALUE io_spec_rb_thread_fd_select_read(VALUE self, VALUE io) { + int fd = io_spec_get_fd(io); + + rb_fdset_t fds; + rb_fd_init(&fds); + rb_fd_set(fd, &fds); + + int r = rb_thread_fd_select(fd + 1, &fds, NULL, NULL, NULL); + rb_fd_term(&fds); + return INT2FIX(r); +} + +VALUE io_spec_rb_thread_fd_select_write(VALUE self, VALUE io) { + int fd = io_spec_get_fd(io); + + rb_fdset_t fds; + rb_fd_init(&fds); + rb_fd_set(fd, &fds); + + int r = rb_thread_fd_select(fd + 1, NULL, &fds, NULL, NULL); + rb_fd_term(&fds); + return INT2FIX(r); +} + +VALUE io_spec_rb_thread_fd_select_timeout(VALUE self, VALUE io) { + int fd = io_spec_get_fd(io); + + struct timeval timeout; + timeout.tv_sec = 10; + timeout.tv_usec = 20; + + rb_fdset_t fds; + rb_fd_init(&fds); + rb_fd_set(fd, &fds); + + int r = rb_thread_fd_select(fd + 1, NULL, &fds, NULL, &timeout); + rb_fd_term(&fds); + return INT2FIX(r); +} + +VALUE io_spec_rb_io_binmode(VALUE self, VALUE io) { + return rb_io_binmode(io); +} + +VALUE io_spec_rb_fd_fix_cloexec(VALUE self, VALUE io) { + rb_fd_fix_cloexec(io_spec_get_fd(io)); + return Qnil; +} + +VALUE io_spec_rb_cloexec_open(VALUE self, VALUE path, VALUE flags, VALUE mode) { + const char *pathname = StringValuePtr(path); + int fd = rb_cloexec_open(pathname, FIX2INT(flags), FIX2INT(mode)); + return rb_funcall(rb_cIO, rb_intern("for_fd"), 1, INT2FIX(fd)); +} + +VALUE io_spec_rb_io_close(VALUE self, VALUE io) { + return rb_io_close(io); +} + +VALUE io_spec_rb_io_set_nonblock(VALUE self, VALUE io) { + rb_io_t* fp; +#ifdef F_GETFL + int flags; +#endif + GetOpenFile(io, fp); + rb_io_set_nonblock(fp); +#ifdef F_GETFL + flags = fcntl(io_spec_get_fd(io), F_GETFL, 0); + return flags & O_NONBLOCK ? Qtrue : Qfalse; +#else + return Qfalse; +#endif +} + +/* + * this is needed to ensure rb_io_wait_*able functions behave + * predictably because errno may be set to unexpected values + * otherwise. + */ +static VALUE io_spec_errno_set(VALUE self, VALUE val) { + int e = NUM2INT(val); + errno = e; + return val; +} + +VALUE io_spec_mode_sync_flag(VALUE self, VALUE io) { + int mode; +#ifdef RUBY_VERSION_IS_3_3 + mode = rb_io_mode(io); +#else + rb_io_t *fp; + GetOpenFile(io, fp); + mode = fp->mode; +#endif + if (mode & FMODE_SYNC) { + return Qtrue; + } else { + return Qfalse; + } +} + +#if defined(RUBY_VERSION_IS_3_3) || defined(TRUFFLERUBY) +static VALUE io_spec_rb_io_mode(VALUE self, VALUE io) { + return INT2FIX(rb_io_mode(io)); +} + +static VALUE io_spec_rb_io_path(VALUE self, VALUE io) { + return rb_io_path(io); +} + +static VALUE io_spec_rb_io_closed_p(VALUE self, VALUE io) { + return rb_io_closed_p(io); +} + +static VALUE io_spec_rb_io_open_descriptor(VALUE self, VALUE klass, VALUE descriptor, VALUE mode, VALUE path, VALUE timeout, VALUE internal_encoding, VALUE external_encoding, VALUE ecflags, VALUE ecopts) { + struct rb_io_encoding io_encoding; + + io_encoding.enc = rb_to_encoding(internal_encoding); + io_encoding.enc2 = rb_to_encoding(external_encoding); + io_encoding.ecflags = FIX2INT(ecflags); + io_encoding.ecopts = ecopts; + + return rb_io_open_descriptor(klass, FIX2INT(descriptor), FIX2INT(mode), path, timeout, &io_encoding); +} + +static VALUE io_spec_rb_io_open_descriptor_without_encoding(VALUE self, VALUE klass, VALUE descriptor, VALUE mode, VALUE path, VALUE timeout) { + return rb_io_open_descriptor(klass, FIX2INT(descriptor), FIX2INT(mode), path, timeout, NULL); +} +#endif + +void Init_io_spec(void) { + VALUE cls = rb_define_class("CApiIOSpecs", rb_cObject); + rb_define_method(cls, "GetOpenFile_fd", io_spec_GetOpenFile_fd, 1); + rb_define_method(cls, "rb_io_addstr", io_spec_rb_io_addstr, 2); + rb_define_method(cls, "rb_io_printf", io_spec_rb_io_printf, 2); + rb_define_method(cls, "rb_io_print", io_spec_rb_io_print, 2); + rb_define_method(cls, "rb_io_puts", io_spec_rb_io_puts, 2); + rb_define_method(cls, "rb_io_write", io_spec_rb_io_write, 2); + rb_define_method(cls, "rb_io_close", io_spec_rb_io_close, 1); + rb_define_method(cls, "rb_io_check_io", io_spec_rb_io_check_io, 1); + rb_define_method(cls, "rb_io_check_readable", io_spec_rb_io_check_readable, 1); + rb_define_method(cls, "rb_io_check_writable", io_spec_rb_io_check_writable, 1); + rb_define_method(cls, "rb_io_check_closed", io_spec_rb_io_check_closed, 1); + rb_define_method(cls, "rb_io_set_nonblock", io_spec_rb_io_set_nonblock, 1); + rb_define_method(cls, "rb_io_taint_check", io_spec_rb_io_taint_check, 1); + rb_define_method(cls, "rb_io_wait_readable", io_spec_rb_io_wait_readable, 2); + rb_define_method(cls, "rb_io_wait_writable", io_spec_rb_io_wait_writable, 1); + rb_define_method(cls, "rb_io_maybe_wait_writable", io_spec_rb_io_maybe_wait_writable, 3); + rb_define_method(cls, "rb_io_maybe_wait_readable", io_spec_rb_io_maybe_wait_readable, 4); + rb_define_method(cls, "rb_io_maybe_wait", io_spec_rb_io_maybe_wait, 4); + rb_define_method(cls, "rb_thread_wait_fd", io_spec_rb_thread_wait_fd, 1); + rb_define_method(cls, "rb_thread_fd_writable", io_spec_rb_thread_fd_writable, 1); + rb_define_method(cls, "rb_thread_fd_select_read", io_spec_rb_thread_fd_select_read, 1); + rb_define_method(cls, "rb_thread_fd_select_write", io_spec_rb_thread_fd_select_write, 1); + rb_define_method(cls, "rb_thread_fd_select_timeout", io_spec_rb_thread_fd_select_timeout, 1); + rb_define_method(cls, "rb_wait_for_single_fd", io_spec_rb_wait_for_single_fd, 4); + rb_define_method(cls, "rb_io_binmode", io_spec_rb_io_binmode, 1); + rb_define_method(cls, "rb_fd_fix_cloexec", io_spec_rb_fd_fix_cloexec, 1); + rb_define_method(cls, "rb_cloexec_open", io_spec_rb_cloexec_open, 3); + rb_define_method(cls, "errno=", io_spec_errno_set, 1); + rb_define_method(cls, "rb_io_mode_sync_flag", io_spec_mode_sync_flag, 1); +#if defined(RUBY_VERSION_IS_3_3) || defined(TRUFFLERUBY) + rb_define_method(cls, "rb_io_mode", io_spec_rb_io_mode, 1); + rb_define_method(cls, "rb_io_path", io_spec_rb_io_path, 1); + rb_define_method(cls, "rb_io_closed_p", io_spec_rb_io_closed_p, 1); + rb_define_method(cls, "rb_io_open_descriptor", io_spec_rb_io_open_descriptor, 9); + rb_define_method(cls, "rb_io_open_descriptor_without_encoding", io_spec_rb_io_open_descriptor_without_encoding, 5); + rb_define_const(cls, "FMODE_READABLE", INT2FIX(FMODE_READABLE)); + rb_define_const(cls, "FMODE_WRITABLE", INT2FIX(FMODE_WRITABLE)); + rb_define_const(cls, "FMODE_BINMODE", INT2FIX(FMODE_BINMODE)); + rb_define_const(cls, "FMODE_TEXTMODE", INT2FIX(FMODE_TEXTMODE)); + rb_define_const(cls, "ECONV_UNIVERSAL_NEWLINE_DECORATOR", INT2FIX(ECONV_UNIVERSAL_NEWLINE_DECORATOR)); +#endif +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/kernel_spec.c b/spec/ruby/optional/capi/ext/kernel_spec.c new file mode 100644 index 0000000000..a8fed21b59 --- /dev/null +++ b/spec/ruby/optional/capi/ext/kernel_spec.c @@ -0,0 +1,452 @@ +#include "ruby.h" +#include "rubyspec.h" + +#include <errno.h> + +#ifdef __cplusplus +extern "C" { +#endif + +static VALUE kernel_spec_call_proc(VALUE arg_array) { + VALUE arg = rb_ary_pop(arg_array); + VALUE proc = rb_ary_pop(arg_array); + return rb_funcall(proc, rb_intern("call"), 1, arg); +} + +static VALUE kernel_spec_rb_block_given_p(VALUE self) { + return rb_block_given_p() ? Qtrue : Qfalse; +} + +VALUE kernel_spec_rb_need_block(VALUE self) { + rb_need_block(); + return Qnil; +} + +VALUE kernel_spec_rb_block_proc(VALUE self) { + return rb_block_proc(); +} + +VALUE kernel_spec_rb_block_lambda(VALUE self) { + return rb_block_lambda(); +} + +VALUE block_call_inject(RB_BLOCK_CALL_FUNC_ARGLIST(yield_value, data2)) { + /* yield_value yields the first block argument */ + VALUE elem = yield_value; + VALUE elem_incr = INT2FIX(FIX2INT(elem) + 1); + return elem_incr; +} + +VALUE kernel_spec_rb_block_call(VALUE self, VALUE ary) { + return rb_block_call(ary, rb_intern("map"), 0, NULL, block_call_inject, Qnil); +} + +VALUE block_call_inject_multi_arg(RB_BLOCK_CALL_FUNC_ARGLIST(yield_value, data2)) { + /* yield_value yields the first block argument */ + VALUE sum = yield_value; + VALUE elem = argv[1]; + + return INT2FIX(FIX2INT(sum) + FIX2INT(elem)); +} + +VALUE kernel_spec_rb_block_call_multi_arg(VALUE self, VALUE ary) { + VALUE method_args[1]; + method_args[0] = INT2FIX(0); + return rb_block_call(ary, rb_intern("inject"), 1, method_args, block_call_inject_multi_arg, Qnil); +} + +static VALUE return_extra_data(RB_BLOCK_CALL_FUNC_ARGLIST(yield_value, extra_data)) { + return extra_data; +} + +VALUE rb_block_call_extra_data(VALUE self, VALUE object) { + return rb_block_call(object, rb_intern("instance_exec"), 0, NULL, return_extra_data, object); +} + +VALUE kernel_spec_rb_block_call_no_func(VALUE self, VALUE ary) { + return rb_block_call(ary, rb_intern("map"), 0, NULL, (rb_block_call_func_t)NULL, Qnil); +} + +VALUE kernel_spec_rb_frame_this_func(VALUE self) { + return ID2SYM(rb_frame_this_func()); +} + +VALUE kernel_spec_rb_category_warn_deprecated(VALUE self) { + rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "foo"); + return Qnil; +} + +VALUE kernel_spec_rb_category_warn_deprecated_with_integer_extra_value(VALUE self, VALUE value) { + rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "foo %d", FIX2INT(value)); + return Qnil; +} + +VALUE kernel_spec_rb_ensure(VALUE self, VALUE main_proc, VALUE arg, + VALUE ensure_proc, VALUE arg2) { + VALUE main_array, ensure_array; + + main_array = rb_ary_new(); + rb_ary_push(main_array, main_proc); + rb_ary_push(main_array, arg); + + ensure_array = rb_ary_new(); + rb_ary_push(ensure_array, ensure_proc); + rb_ary_push(ensure_array, arg2); + + return rb_ensure(kernel_spec_call_proc, main_array, + kernel_spec_call_proc, ensure_array); +} + +VALUE kernel_spec_call_proc_with_catch(RB_BLOCK_CALL_FUNC_ARGLIST(arg, data)) { + return rb_funcall(data, rb_intern("call"), 0); +} + +VALUE kernel_spec_rb_catch(VALUE self, VALUE sym, VALUE main_proc) { + return rb_catch(StringValuePtr(sym), kernel_spec_call_proc_with_catch, main_proc); +} + +VALUE kernel_spec_call_proc_with_catch_obj(RB_BLOCK_CALL_FUNC_ARGLIST(arg, data)) { + return rb_funcall(data, rb_intern("call"), 0); +} + +VALUE kernel_spec_rb_catch_obj(VALUE self, VALUE obj, VALUE main_proc) { + return rb_catch_obj(obj, kernel_spec_call_proc_with_catch_obj, main_proc); +} + +VALUE kernel_spec_rb_eval_string(VALUE self, VALUE str) { + return rb_eval_string(RSTRING_PTR(str)); +} + +#ifndef RUBY_VERSION_IS_4_0 +VALUE kernel_spec_rb_eval_cmd_kw(VALUE self, VALUE cmd, VALUE args, VALUE kw_splat) { + return rb_eval_cmd_kw(cmd, args, NUM2INT(kw_splat)); +} +#endif + +VALUE kernel_spec_rb_raise(VALUE self, VALUE hash) { + rb_hash_aset(hash, ID2SYM(rb_intern("stage")), ID2SYM(rb_intern("before"))); + if (self != Qundef) + rb_raise(rb_eTypeError, "Wrong argument type %s (expected %s)", "Integer", "String"); + rb_hash_aset(hash, ID2SYM(rb_intern("stage")), ID2SYM(rb_intern("after"))); + return Qnil; +} + +VALUE kernel_spec_rb_throw(VALUE self, VALUE result) { + if (self != Qundef) rb_throw("foo", result); + return ID2SYM(rb_intern("rb_throw_failed")); +} + +VALUE kernel_spec_rb_throw_obj(VALUE self, VALUE obj, VALUE result) { + if (self != Qundef) rb_throw_obj(obj, result); + return ID2SYM(rb_intern("rb_throw_failed")); +} + +VALUE kernel_spec_rb_errinfo(VALUE self) { + return rb_errinfo(); +} + +VALUE kernel_spec_rb_set_errinfo(VALUE self, VALUE exc) { + rb_set_errinfo(exc); + return Qnil; +} + +static VALUE kernel_spec_call_proc_with_raised_exc(VALUE arg_array, VALUE raised_exc) { + VALUE argv[2]; + int argc; + + VALUE arg = rb_ary_pop(arg_array); + VALUE proc = rb_ary_pop(arg_array); + + argv[0] = arg; + argv[1] = raised_exc; + + argc = 2; + + return rb_funcallv(proc, rb_intern("call"), argc, argv); +} + +VALUE kernel_spec_rb_rescue(VALUE self, VALUE main_proc, VALUE arg, + VALUE raise_proc, VALUE arg2) { + VALUE main_array, raise_array; + + main_array = rb_ary_new(); + rb_ary_push(main_array, main_proc); + rb_ary_push(main_array, arg); + + if (raise_proc == Qnil) { + return rb_rescue(kernel_spec_call_proc, main_array, NULL, arg2); + } + + raise_array = rb_ary_new(); + rb_ary_push(raise_array, raise_proc); + rb_ary_push(raise_array, arg2); + + return rb_rescue(kernel_spec_call_proc, main_array, + kernel_spec_call_proc_with_raised_exc, raise_array); +} + +VALUE kernel_spec_rb_rescue2(int argc, VALUE *args, VALUE self) { + VALUE main_array, raise_array; + + main_array = rb_ary_new(); + rb_ary_push(main_array, args[0]); + rb_ary_push(main_array, args[1]); + + raise_array = rb_ary_new(); + rb_ary_push(raise_array, args[2]); + rb_ary_push(raise_array, args[3]); + + return rb_rescue2(kernel_spec_call_proc, main_array, + kernel_spec_call_proc_with_raised_exc, raise_array, args[4], args[5], (VALUE)0); +} + +static VALUE kernel_spec_rb_protect_yield(VALUE self, VALUE obj, VALUE ary) { + int status = 0; + VALUE res = rb_protect(rb_yield, obj, &status); + rb_ary_store(ary, 0, INT2NUM(23)); + rb_ary_store(ary, 1, res); + if (status) { + rb_jump_tag(status); + } + return res; +} + +static VALUE kernel_spec_rb_protect_ignore_status(VALUE self, VALUE obj, VALUE ary) { + int status = 0; + VALUE res = rb_protect(rb_yield, obj, &status); + rb_ary_store(ary, 0, INT2NUM(23)); + rb_ary_store(ary, 1, res); + return rb_errinfo(); +} + +static VALUE kernel_spec_rb_protect_null_status(VALUE self, VALUE obj) { + return rb_protect(rb_yield, obj, NULL); +} + +static VALUE kernel_spec_rb_eval_string_protect(VALUE self, VALUE str, VALUE ary) { + int status = 0; + VALUE res = rb_eval_string_protect(RSTRING_PTR(str), &status); + rb_ary_store(ary, 0, INT2NUM(23)); + rb_ary_store(ary, 1, res); + if (status) { + rb_jump_tag(status); + } + return res; +} + +VALUE kernel_spec_rb_sys_fail(VALUE self, VALUE msg) { + errno = 1; + if (msg == Qnil) { + rb_sys_fail(NULL); + } else if (self != Qundef) { + rb_sys_fail(StringValuePtr(msg)); + } + return Qnil; +} + +VALUE kernel_spec_rb_syserr_fail(VALUE self, VALUE err, VALUE msg) { + if (msg == Qnil) { + rb_syserr_fail(NUM2INT(err), NULL); + } else if (self != Qundef) { + rb_syserr_fail(NUM2INT(err), StringValuePtr(msg)); + } + return Qnil; +} + +VALUE kernel_spec_rb_syserr_fail_str(VALUE self, VALUE err, VALUE msg) { + if (self != Qundef) { + rb_syserr_fail_str(NUM2INT(err), msg); + } + return Qnil; +} + +VALUE kernel_spec_rb_warn(VALUE self, VALUE msg) { + rb_warn("%s", StringValuePtr(msg)); + return Qnil; +} + +static VALUE kernel_spec_rb_yield(VALUE self, VALUE obj) { + return rb_yield(obj); +} + +static VALUE kernel_spec_rb_yield_each(int argc, VALUE *args, VALUE self) { + int i; + for(i = 0; i < 4; i++) { + rb_yield(INT2FIX(i)); + } + return INT2FIX(4); +} + +static VALUE kernel_spec_rb_yield_define_each(VALUE self, VALUE cls) { + rb_define_method(cls, "each", kernel_spec_rb_yield_each, -1); + return Qnil; +} + +static int kernel_cb(const void *a, const void *b) { + rb_yield(Qtrue); + return 0; +} + +static VALUE kernel_indirected(int (*compar)(const void *, const void *)) { + int bob[] = { 1, 1, 2, 3, 5, 8, 13 }; + qsort(bob, 7, sizeof(int), compar); + return Qfalse; +} + +static VALUE kernel_spec_rb_yield_indirected(VALUE self, VALUE obj) { + return kernel_indirected(kernel_cb); +} + +static VALUE kernel_spec_rb_yield_splat(VALUE self, VALUE ary) { + return rb_yield_splat(ary); +} + +static VALUE kernel_spec_rb_yield_values(VALUE self, VALUE obj1, VALUE obj2) { + return rb_yield_values(2, obj1, obj2); +} + +static VALUE kernel_spec_rb_yield_values2(VALUE self, VALUE ary) { + long len = RARRAY_LEN(ary); + VALUE *args = (VALUE*)alloca(sizeof(VALUE) * len); + for (int i = 0; i < len; i++) { + args[i] = rb_ary_entry(ary, i); + } + return rb_yield_values2((int)len, args); +} + +static VALUE do_rec(VALUE obj, VALUE arg, int is_rec) { + if (is_rec) { + return obj; + } else if (arg == Qtrue) { + return rb_exec_recursive(do_rec, obj, Qnil); + } else { + return Qnil; + } +} + +static VALUE kernel_spec_rb_exec_recursive(VALUE self, VALUE obj) { + return rb_exec_recursive(do_rec, obj, Qtrue); +} + +static void write_io(VALUE io) { + rb_funcall(io, rb_intern("write"), 1, rb_str_new2("in write_io")); +} + +static VALUE kernel_spec_rb_set_end_proc(VALUE self, VALUE io) { + rb_set_end_proc(write_io, io); + return Qnil; +} + +static VALUE kernel_spec_rb_f_sprintf(VALUE self, VALUE ary) { + return rb_f_sprintf((int)RARRAY_LEN(ary), RARRAY_PTR(ary)); +} + +static VALUE kernel_spec_rb_str_format(VALUE self, VALUE count, VALUE ary, VALUE format) { + return rb_str_format(FIX2INT(count), RARRAY_PTR(ary), format); +} + +static VALUE kernel_spec_rb_make_backtrace(VALUE self) { + return rb_make_backtrace(); +} + +static VALUE kernel_spec_rb_funcallv(VALUE self, VALUE obj, VALUE method, VALUE args) { + return rb_funcallv(obj, SYM2ID(method), RARRAY_LENINT(args), RARRAY_PTR(args)); +} + +static VALUE kernel_spec_rb_funcallv_kw(VALUE self, VALUE obj, VALUE method, VALUE args) { + return rb_funcallv_kw(obj, SYM2ID(method), RARRAY_LENINT(args), RARRAY_PTR(args), RB_PASS_KEYWORDS); +} + +static VALUE kernel_spec_rb_keyword_given_p(int argc, VALUE *args, VALUE self) { + return rb_keyword_given_p() ? Qtrue : Qfalse; +} + +static VALUE kernel_spec_rb_funcallv_public(VALUE self, VALUE obj, VALUE method) { + return rb_funcallv_public(obj, SYM2ID(method), 0, NULL); +} + +static VALUE kernel_spec_rb_funcall_with_block(VALUE self, VALUE obj, VALUE method, VALUE args, VALUE block) { + return rb_funcall_with_block(obj, SYM2ID(method), RARRAY_LENINT(args), RARRAY_PTR(args), block); +} + +static VALUE kernel_spec_rb_funcall_with_block_kw(VALUE self, VALUE obj, VALUE method, VALUE args, VALUE block) { + return rb_funcall_with_block_kw(obj, SYM2ID(method), RARRAY_LENINT(args), RARRAY_PTR(args), block, RB_PASS_KEYWORDS); +} + +static VALUE kernel_spec_rb_funcall_many_args(VALUE self, VALUE obj, VALUE method) { + return rb_funcall(obj, SYM2ID(method), 15, + INT2FIX(15), INT2FIX(14), INT2FIX(13), INT2FIX(12), INT2FIX(11), + INT2FIX(10), INT2FIX(9), INT2FIX(8), INT2FIX(7), INT2FIX(6), + INT2FIX(5), INT2FIX(4), INT2FIX(3), INT2FIX(2), INT2FIX(1)); +} + +static VALUE kernel_spec_rb_check_funcall(VALUE self, VALUE receiver, VALUE method, VALUE args) { + VALUE ret = rb_check_funcall(receiver, SYM2ID(method), RARRAY_LENINT(args), RARRAY_PTR(args)); + if (ret == Qundef) { + return ID2SYM(rb_intern("Qundef")); + } else { + return ret; + } +} + +void Init_kernel_spec(void) { + VALUE cls = rb_define_class("CApiKernelSpecs", rb_cObject); + rb_define_method(cls, "rb_block_given_p", kernel_spec_rb_block_given_p, 0); + rb_define_method(cls, "rb_need_block", kernel_spec_rb_need_block, 0); + rb_define_method(cls, "rb_block_call", kernel_spec_rb_block_call, 1); + rb_define_method(cls, "rb_block_call_multi_arg", kernel_spec_rb_block_call_multi_arg, 1); + rb_define_method(cls, "rb_block_call_no_func", kernel_spec_rb_block_call_no_func, 1); + rb_define_method(cls, "rb_block_call_extra_data", rb_block_call_extra_data, 1); + rb_define_method(cls, "rb_block_proc", kernel_spec_rb_block_proc, 0); + rb_define_method(cls, "rb_block_lambda", kernel_spec_rb_block_lambda, 0); + rb_define_method(cls, "rb_frame_this_func_test", kernel_spec_rb_frame_this_func, 0); + rb_define_method(cls, "rb_frame_this_func_test_again", kernel_spec_rb_frame_this_func, 0); + rb_define_method(cls, "rb_category_warn_deprecated", kernel_spec_rb_category_warn_deprecated, 0); + rb_define_method(cls, "rb_category_warn_deprecated_with_integer_extra_value", kernel_spec_rb_category_warn_deprecated_with_integer_extra_value, 1); + rb_define_method(cls, "rb_ensure", kernel_spec_rb_ensure, 4); + rb_define_method(cls, "rb_eval_string", kernel_spec_rb_eval_string, 1); +#ifndef RUBY_VERSION_IS_4_0 + rb_define_method(cls, "rb_eval_cmd_kw", kernel_spec_rb_eval_cmd_kw, 3); +#endif + rb_define_method(cls, "rb_raise", kernel_spec_rb_raise, 1); + rb_define_method(cls, "rb_throw", kernel_spec_rb_throw, 1); + rb_define_method(cls, "rb_throw_obj", kernel_spec_rb_throw_obj, 2); + rb_define_method(cls, "rb_errinfo", kernel_spec_rb_errinfo, 0); + rb_define_method(cls, "rb_set_errinfo", kernel_spec_rb_set_errinfo, 1); + rb_define_method(cls, "rb_rescue", kernel_spec_rb_rescue, 4); + rb_define_method(cls, "rb_rescue", kernel_spec_rb_rescue, 4); + rb_define_method(cls, "rb_rescue2", kernel_spec_rb_rescue2, -1); + rb_define_method(cls, "rb_protect_yield", kernel_spec_rb_protect_yield, 2); + rb_define_method(cls, "rb_protect_ignore_status", kernel_spec_rb_protect_ignore_status, 2); + rb_define_method(cls, "rb_protect_null_status", kernel_spec_rb_protect_null_status, 1); + rb_define_method(cls, "rb_eval_string_protect", kernel_spec_rb_eval_string_protect, 2); + rb_define_method(cls, "rb_catch", kernel_spec_rb_catch, 2); + rb_define_method(cls, "rb_catch_obj", kernel_spec_rb_catch_obj, 2); + rb_define_method(cls, "rb_sys_fail", kernel_spec_rb_sys_fail, 1); + rb_define_method(cls, "rb_syserr_fail", kernel_spec_rb_syserr_fail, 2); + rb_define_method(cls, "rb_syserr_fail_str", kernel_spec_rb_syserr_fail_str, 2); + rb_define_method(cls, "rb_warn", kernel_spec_rb_warn, 1); + rb_define_method(cls, "rb_yield", kernel_spec_rb_yield, 1); + rb_define_method(cls, "rb_yield_indirected", kernel_spec_rb_yield_indirected, 1); + rb_define_method(cls, "rb_yield_define_each", kernel_spec_rb_yield_define_each, 1); + rb_define_method(cls, "rb_yield_values", kernel_spec_rb_yield_values, 2); + rb_define_method(cls, "rb_yield_values2", kernel_spec_rb_yield_values2, 1); + rb_define_method(cls, "rb_yield_splat", kernel_spec_rb_yield_splat, 1); + rb_define_method(cls, "rb_exec_recursive", kernel_spec_rb_exec_recursive, 1); + rb_define_method(cls, "rb_set_end_proc", kernel_spec_rb_set_end_proc, 1); + rb_define_method(cls, "rb_f_sprintf", kernel_spec_rb_f_sprintf, 1); + rb_define_method(cls, "rb_str_format", kernel_spec_rb_str_format, 3); + rb_define_method(cls, "rb_make_backtrace", kernel_spec_rb_make_backtrace, 0); + rb_define_method(cls, "rb_funcallv", kernel_spec_rb_funcallv, 3); + rb_define_method(cls, "rb_funcallv_kw", kernel_spec_rb_funcallv_kw, 3); + rb_define_method(cls, "rb_keyword_given_p", kernel_spec_rb_keyword_given_p, -1); + rb_define_method(cls, "rb_funcallv_public", kernel_spec_rb_funcallv_public, 2); + rb_define_method(cls, "rb_funcall_many_args", kernel_spec_rb_funcall_many_args, 2); + rb_define_method(cls, "rb_funcall_with_block", kernel_spec_rb_funcall_with_block, 4); + rb_define_method(cls, "rb_funcall_with_block_kw", kernel_spec_rb_funcall_with_block_kw, 4); + rb_define_method(cls, "rb_check_funcall", kernel_spec_rb_check_funcall, 3); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/language_spec.c b/spec/ruby/optional/capi/ext/language_spec.c new file mode 100644 index 0000000000..749c188956 --- /dev/null +++ b/spec/ruby/optional/capi/ext/language_spec.c @@ -0,0 +1,42 @@ +#include "ruby.h" +#include "rubyspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static VALUE language_spec_switch(VALUE self, VALUE value) { + if (value == ID2SYM(rb_intern("undef"))) { + value = Qundef; + } + + switch (value) { + case Qtrue: + return ID2SYM(rb_intern("true")); + case Qfalse: + return ID2SYM(rb_intern("false")); + case Qnil: + return ID2SYM(rb_intern("nil")); + case Qundef: + return ID2SYM(rb_intern("undef")); + default: + return ID2SYM(rb_intern("default")); + } +} + +/* Defining a local variable rb_mProcess which already exists as a global variable + * For instance eventmachine does this in Init_rubyeventmachine() */ +static VALUE language_spec_global_local_var(VALUE self) { + VALUE rb_mProcess = rb_const_get(rb_cObject, rb_intern("Process")); + return rb_mProcess; +} + +void Init_language_spec(void) { + VALUE cls = rb_define_class("CApiLanguageSpecs", rb_cObject); + rb_define_method(cls, "switch", language_spec_switch, 1); + rb_define_method(cls, "global_local_var", language_spec_global_local_var, 0); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/marshal_spec.c b/spec/ruby/optional/capi/ext/marshal_spec.c new file mode 100644 index 0000000000..ea8e3d5a07 --- /dev/null +++ b/spec/ruby/optional/capi/ext/marshal_spec.c @@ -0,0 +1,24 @@ +#include "ruby.h" +#include "rubyspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +VALUE marshal_spec_rb_marshal_dump(VALUE self, VALUE obj, VALUE port) { + return rb_marshal_dump(obj, port); +} + +VALUE marshal_spec_rb_marshal_load(VALUE self, VALUE data) { + return rb_marshal_load(data); +} + +void Init_marshal_spec(void) { + VALUE cls = rb_define_class("CApiMarshalSpecs", rb_cObject); + rb_define_method(cls, "rb_marshal_dump", marshal_spec_rb_marshal_dump, 2); + rb_define_method(cls, "rb_marshal_load", marshal_spec_rb_marshal_load, 1); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/module_spec.c b/spec/ruby/optional/capi/ext/module_spec.c new file mode 100644 index 0000000000..12bcf99983 --- /dev/null +++ b/spec/ruby/optional/capi/ext/module_spec.c @@ -0,0 +1,176 @@ +#include "ruby.h" +#include "rubyspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static VALUE module_specs_test_method(VALUE self) { + return ID2SYM(rb_intern("test_method")); +} + +static VALUE module_specs_const_defined(VALUE self, VALUE klass, VALUE id) { + return rb_const_defined(klass, SYM2ID(id)) ? Qtrue : Qfalse; +} + +static VALUE module_specs_const_defined_at(VALUE self, VALUE klass, VALUE id) { + return rb_const_defined_at(klass, SYM2ID(id)) ? Qtrue : Qfalse; +} + +static VALUE module_specs_const_get(VALUE self, VALUE klass, VALUE val) { + return rb_const_get(klass, SYM2ID(val)); +} + +static VALUE module_specs_const_get_at(VALUE self, VALUE klass, VALUE val) { + return rb_const_get_at(klass, SYM2ID(val)); +} + +static VALUE module_specs_const_get_from(VALUE self, VALUE klass, VALUE val) { + return rb_const_get_from(klass, SYM2ID(val)); +} + +static VALUE module_specs_const_set(VALUE self, VALUE klass, VALUE name, VALUE val) { + rb_const_set(klass, SYM2ID(name), val); + return Qnil; +} + +static VALUE module_specs_rb_define_alias(VALUE self, VALUE obj, + VALUE new_name, VALUE old_name) { + + rb_define_alias(obj, RSTRING_PTR(new_name), RSTRING_PTR(old_name)); + return Qnil; +} + +static VALUE module_specs_rb_alias(VALUE self, VALUE obj, + VALUE new_name, VALUE old_name) { + + rb_alias(obj, SYM2ID(new_name), SYM2ID(old_name)); + return Qnil; +} + +static VALUE module_specs_rb_define_module(VALUE self, VALUE name) { + return rb_define_module(RSTRING_PTR(name)); +} + +static VALUE module_specs_rb_define_module_under(VALUE self, VALUE outer, VALUE name) { + return rb_define_module_under(outer, RSTRING_PTR(name)); +} + +static VALUE module_specs_define_const(VALUE self, VALUE klass, VALUE str_name, VALUE val) { + rb_define_const(klass, RSTRING_PTR(str_name), val); + return Qnil; +} + +static VALUE module_specs_define_global_const(VALUE self, VALUE str_name, VALUE obj) { + rb_define_global_const(RSTRING_PTR(str_name), obj); + return Qnil; +} + +static VALUE module_specs_rb_define_global_function(VALUE self, VALUE str_name) { + rb_define_global_function(RSTRING_PTR(str_name), module_specs_test_method, 0); + return Qnil; +} + +static VALUE module_specs_rb_define_method(VALUE self, VALUE cls, VALUE str_name) { + rb_define_method(cls, RSTRING_PTR(str_name), module_specs_test_method, 0); + return Qnil; +} + +static VALUE module_specs_method_var_args_1(int argc, VALUE *argv, VALUE self) { + VALUE ary = rb_ary_new(); + int i; + for (i = 0; i < argc; i++) { + rb_ary_push(ary, argv[i]); + } + return ary; +} + +static VALUE module_specs_method_var_args_2(VALUE self, VALUE argv) { + return argv; +} + +static VALUE module_specs_rb_define_method_1required(VALUE self, VALUE arg1) { + return arg1; +} + +static VALUE module_specs_rb_define_method_2required(VALUE self, VALUE arg1, VALUE arg2) { + return arg2; +} + +static VALUE module_specs_rb_define_module_function(VALUE self, VALUE cls, VALUE str_name) { + rb_define_module_function(cls, RSTRING_PTR(str_name), module_specs_test_method, 0); + return Qnil; +} + +static VALUE module_specs_rb_define_private_method(VALUE self, VALUE cls, VALUE str_name) { + rb_define_private_method(cls, RSTRING_PTR(str_name), module_specs_test_method, 0); + return Qnil; +} + +static VALUE module_specs_rb_define_protected_method(VALUE self, VALUE cls, VALUE str_name) { + rb_define_protected_method(cls, RSTRING_PTR(str_name), module_specs_test_method, 0); + return Qnil; +} + +static VALUE module_specs_rb_define_singleton_method(VALUE self, VALUE cls, VALUE str_name) { + rb_define_singleton_method(cls, RSTRING_PTR(str_name), module_specs_test_method, 0); + return Qnil; +} + +static VALUE module_specs_rb_undef_method(VALUE self, VALUE cls, VALUE str_name) { + rb_undef_method(cls, RSTRING_PTR(str_name)); + return Qnil; +} + +static VALUE module_specs_rb_undef(VALUE self, VALUE cls, VALUE symbol_name) { + rb_undef(cls, SYM2ID(symbol_name)); + return Qnil; +} + +static VALUE module_specs_rbclass2name(VALUE self, VALUE klass) { + return rb_str_new2(rb_class2name(klass)); +} + +static VALUE module_specs_rb_mod_ancestors(VALUE self, VALUE klass) { + return rb_mod_ancestors(klass); +} + +void Init_module_spec(void) { + VALUE cls = rb_define_class("CApiModuleSpecs", rb_cObject); + rb_define_method(cls, "rb_const_defined", module_specs_const_defined, 2); + rb_define_method(cls, "rb_const_defined_at", module_specs_const_defined_at, 2); + rb_define_method(cls, "rb_const_get", module_specs_const_get, 2); + rb_define_method(cls, "rb_const_get_at", module_specs_const_get_at, 2); + rb_define_method(cls, "rb_const_get_from", module_specs_const_get_from, 2); + rb_define_method(cls, "rb_const_set", module_specs_const_set, 3); + rb_define_method(cls, "rb_define_alias", module_specs_rb_define_alias, 3); + rb_define_method(cls, "rb_alias", module_specs_rb_alias, 3); + rb_define_method(cls, "rb_define_module", module_specs_rb_define_module, 1); + rb_define_method(cls, "rb_define_module_under", module_specs_rb_define_module_under, 2); + rb_define_method(cls, "rb_define_const", module_specs_define_const, 3); + rb_define_method(cls, "rb_define_global_const", module_specs_define_global_const, 2); + rb_define_method(cls, "rb_define_global_function", module_specs_rb_define_global_function, 1); + + rb_define_method(cls, "rb_define_method", module_specs_rb_define_method, 2); + rb_define_method(cls, "rb_define_method_varargs_1", module_specs_method_var_args_1, -1); + rb_define_method(cls, "rb_define_method_varargs_2", module_specs_method_var_args_2, -2); + rb_define_method(cls, "rb_define_method_1required", module_specs_rb_define_method_1required, 1); + rb_define_method(cls, "rb_define_method_2required", module_specs_rb_define_method_2required, 2); + + rb_define_method(cls, "rb_define_module_function", module_specs_rb_define_module_function, 2); + + rb_define_method(cls, "rb_define_private_method", module_specs_rb_define_private_method, 2); + + rb_define_method(cls, "rb_define_protected_method", module_specs_rb_define_protected_method, 2); + + rb_define_method(cls, "rb_define_singleton_method", module_specs_rb_define_singleton_method, 2); + + rb_define_method(cls, "rb_undef_method", module_specs_rb_undef_method, 2); + rb_define_method(cls, "rb_undef", module_specs_rb_undef, 2); + rb_define_method(cls, "rb_class2name", module_specs_rbclass2name, 1); + rb_define_method(cls, "rb_mod_ancestors", module_specs_rb_mod_ancestors, 1); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/module_under_autoload_spec.c b/spec/ruby/optional/capi/ext/module_under_autoload_spec.c new file mode 100644 index 0000000000..b19466e555 --- /dev/null +++ b/spec/ruby/optional/capi/ext/module_under_autoload_spec.c @@ -0,0 +1,15 @@ +#include "ruby.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void Init_module_under_autoload_spec(void) { + VALUE specs = rb_const_get(rb_cObject, rb_intern("CApiModuleSpecs")); + rb_define_module_under(specs, "ModuleUnderAutoload"); + rb_define_module_under(specs, "RubyUnderAutoload"); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/mutex_spec.c b/spec/ruby/optional/capi/ext/mutex_spec.c new file mode 100644 index 0000000000..d2c8f98e89 --- /dev/null +++ b/spec/ruby/optional/capi/ext/mutex_spec.c @@ -0,0 +1,76 @@ +#include "ruby.h" +#include "rubyspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +VALUE mutex_spec_rb_mutex_new(VALUE self) { + return rb_mutex_new(); +} + +VALUE mutex_spec_rb_mutex_locked_p(VALUE self, VALUE mutex) { + return rb_mutex_locked_p(mutex); +} + +VALUE mutex_spec_rb_mutex_trylock(VALUE self, VALUE mutex) { + return rb_mutex_trylock(mutex); +} + +VALUE mutex_spec_rb_mutex_lock(VALUE self, VALUE mutex) { + return rb_mutex_lock(mutex); +} + +VALUE mutex_spec_rb_mutex_unlock(VALUE self, VALUE mutex) { + return rb_mutex_unlock(mutex); +} + +VALUE mutex_spec_rb_mutex_sleep(VALUE self, VALUE mutex, VALUE timeout) { + return rb_mutex_sleep(mutex, timeout); +} + +VALUE mutex_spec_rb_mutex_callback(VALUE arg) { + return rb_funcall(arg, rb_intern("call"), 0); +} + +VALUE mutex_spec_rb_mutex_naughty_callback(VALUE arg) { + int *result = (int *) arg; + return (VALUE) result; +} + +VALUE mutex_spec_rb_mutex_callback_basic(VALUE arg) { + return arg; +} + +VALUE mutex_spec_rb_mutex_synchronize(VALUE self, VALUE mutex, VALUE value) { + return rb_mutex_synchronize(mutex, mutex_spec_rb_mutex_callback, value); +} + +VALUE mutex_spec_rb_mutex_synchronize_with_naughty_callback(VALUE self, VALUE mutex) { + // a naughty callback accepts or returns not a Ruby object but arbitrary value + int arg = 42; + VALUE result = rb_mutex_synchronize(mutex, mutex_spec_rb_mutex_naughty_callback, (VALUE) &arg); + return INT2NUM(*((int *) result)); +} + +VALUE mutex_spec_rb_mutex_synchronize_with_native_callback(VALUE self, VALUE mutex, VALUE value) { + return rb_mutex_synchronize(mutex, mutex_spec_rb_mutex_callback_basic, value); +} + +void Init_mutex_spec(void) { + VALUE cls = rb_define_class("CApiMutexSpecs", rb_cObject); + rb_define_method(cls, "rb_mutex_new", mutex_spec_rb_mutex_new, 0); + rb_define_method(cls, "rb_mutex_locked_p", mutex_spec_rb_mutex_locked_p, 1); + rb_define_method(cls, "rb_mutex_trylock", mutex_spec_rb_mutex_trylock, 1); + rb_define_method(cls, "rb_mutex_lock", mutex_spec_rb_mutex_lock, 1); + rb_define_method(cls, "rb_mutex_unlock", mutex_spec_rb_mutex_unlock, 1); + rb_define_method(cls, "rb_mutex_sleep", mutex_spec_rb_mutex_sleep, 2); + rb_define_method(cls, "rb_mutex_synchronize", mutex_spec_rb_mutex_synchronize, 2); + rb_define_method(cls, "rb_mutex_synchronize_with_naughty_callback", mutex_spec_rb_mutex_synchronize_with_naughty_callback, 1); + rb_define_method(cls, "rb_mutex_synchronize_with_native_callback", mutex_spec_rb_mutex_synchronize_with_native_callback, 2); +} + +#ifdef __cplusplus +} +#endif + diff --git a/spec/ruby/optional/capi/ext/numeric_spec.c b/spec/ruby/optional/capi/ext/numeric_spec.c new file mode 100644 index 0000000000..d3639580a8 --- /dev/null +++ b/spec/ruby/optional/capi/ext/numeric_spec.c @@ -0,0 +1,130 @@ +#include "ruby.h" +#include "rubyspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static VALUE numeric_spec_size_of_VALUE(VALUE self) { + return INT2FIX(sizeof(VALUE)); +} + +static VALUE numeric_spec_size_of_long_long(VALUE self) { + return INT2FIX(sizeof(LONG_LONG)); +} + +static VALUE numeric_spec_NUM2CHR(VALUE self, VALUE value) { + return INT2FIX(NUM2CHR(value)); +} + +static VALUE numeric_spec_rb_int2inum_14(VALUE self) { + return rb_int2inum(14); +} + +static VALUE numeric_spec_rb_uint2inum_14(VALUE self) { + return rb_uint2inum(14); +} + +static VALUE numeric_spec_rb_uint2inum_n14(VALUE self) { + return rb_uint2inum(-14); +} + +static VALUE numeric_spec_rb_Integer(VALUE self, VALUE str) { + return rb_Integer(str); +} + +static VALUE numeric_spec_rb_ll2inum_14(VALUE self) { + return rb_ll2inum(14); +} + +static VALUE numeric_spec_rb_ull2inum_14(VALUE self) { + return rb_ull2inum(14); +} + +static VALUE numeric_spec_rb_ull2inum_n14(VALUE self) { + return rb_ull2inum(-14); +} + +static VALUE numeric_spec_NUM2DBL(VALUE self, VALUE num) { + return rb_float_new(NUM2DBL(num)); +} + +static VALUE numeric_spec_NUM2INT(VALUE self, VALUE num) { + return LONG2NUM(NUM2INT(num)); +} + +static VALUE numeric_spec_INT2NUM(VALUE self, VALUE num) { + return INT2NUM(NUM2INT(num)); +} + +static VALUE numeric_spec_NUM2LONG(VALUE self, VALUE num) { + return LONG2NUM(NUM2LONG(num)); +} + +static VALUE numeric_spec_NUM2SHORT(VALUE self, VALUE num) { + return LONG2NUM(NUM2SHORT(num)); +} + +static VALUE numeric_spec_NUM2UINT(VALUE self, VALUE num) { + return ULONG2NUM(NUM2UINT(num)); +} + +static VALUE numeric_spec_NUM2ULONG(VALUE self, VALUE num) { + return ULONG2NUM(NUM2ULONG(num)); +} + +static VALUE numeric_spec_rb_num_zerodiv(VALUE self) { + rb_num_zerodiv(); + return Qnil; +} + +static VALUE numeric_spec_rb_cmpint(VALUE self, VALUE val, VALUE b) { + return INT2FIX(rb_cmpint(val, val, b)); +} + +static VALUE numeric_spec_rb_num_coerce_bin(VALUE self, VALUE x, VALUE y, VALUE op) { + return rb_num_coerce_bin(x, y, SYM2ID(op)); +} + +static VALUE numeric_spec_rb_num_coerce_cmp(VALUE self, VALUE x, VALUE y, VALUE op) { + return rb_num_coerce_cmp(x, y, SYM2ID(op)); +} + +static VALUE numeric_spec_rb_num_coerce_relop(VALUE self, VALUE x, VALUE y, VALUE op) { + return rb_num_coerce_relop(x, y, SYM2ID(op)); +} + +static VALUE numeric_spec_rb_absint_singlebit_p(VALUE self, VALUE num) { + return INT2FIX(rb_absint_singlebit_p(num)); +} + +void Init_numeric_spec(void) { + VALUE cls = rb_define_class("CApiNumericSpecs", rb_cObject); + rb_define_method(cls, "size_of_VALUE", numeric_spec_size_of_VALUE, 0); + rb_define_method(cls, "size_of_long_long", numeric_spec_size_of_long_long, 0); + rb_define_method(cls, "NUM2CHR", numeric_spec_NUM2CHR, 1); + rb_define_method(cls, "rb_int2inum_14", numeric_spec_rb_int2inum_14, 0); + rb_define_method(cls, "rb_uint2inum_14", numeric_spec_rb_uint2inum_14, 0); + rb_define_method(cls, "rb_uint2inum_n14", numeric_spec_rb_uint2inum_n14, 0); + rb_define_method(cls, "rb_Integer", numeric_spec_rb_Integer, 1); + rb_define_method(cls, "rb_ll2inum_14", numeric_spec_rb_ll2inum_14, 0); + rb_define_method(cls, "rb_ull2inum_14", numeric_spec_rb_ull2inum_14, 0); + rb_define_method(cls, "rb_ull2inum_n14", numeric_spec_rb_ull2inum_n14, 0); + rb_define_method(cls, "NUM2DBL", numeric_spec_NUM2DBL, 1); + rb_define_method(cls, "NUM2INT", numeric_spec_NUM2INT, 1); + rb_define_method(cls, "NUM2LONG", numeric_spec_NUM2LONG, 1); + rb_define_method(cls, "NUM2SHORT", numeric_spec_NUM2SHORT, 1); + rb_define_method(cls, "INT2NUM", numeric_spec_INT2NUM, 1); + rb_define_method(cls, "NUM2UINT", numeric_spec_NUM2UINT, 1); + rb_define_method(cls, "NUM2ULONG", numeric_spec_NUM2ULONG, 1); + rb_define_method(cls, "rb_num_zerodiv", numeric_spec_rb_num_zerodiv, 0); + rb_define_method(cls, "rb_cmpint", numeric_spec_rb_cmpint, 2); + rb_define_method(cls, "rb_num_coerce_bin", numeric_spec_rb_num_coerce_bin, 3); + rb_define_method(cls, "rb_num_coerce_cmp", numeric_spec_rb_num_coerce_cmp, 3); + rb_define_method(cls, "rb_num_coerce_relop", numeric_spec_rb_num_coerce_relop, 3); +rb_define_method(cls, "rb_absint_singlebit_p", numeric_spec_rb_absint_singlebit_p, 1); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/object_spec.c b/spec/ruby/optional/capi/ext/object_spec.c new file mode 100644 index 0000000000..995bc38fcf --- /dev/null +++ b/spec/ruby/optional/capi/ext/object_spec.c @@ -0,0 +1,475 @@ +#include "ruby.h" +#include "rubyspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static VALUE object_spec_FL_ABLE(VALUE self, VALUE obj) { + if (FL_ABLE(obj)) { + return Qtrue; + } else { + return Qfalse; + } +} + +static int object_spec_FL_TEST_flag(VALUE flag_string) { + char *flag_cstr = StringValueCStr(flag_string); + if (strcmp(flag_cstr, "FL_FREEZE") == 0) { + return FL_FREEZE; + } + return 0; +} + +static VALUE object_spec_FL_TEST(VALUE self, VALUE obj, VALUE flag) { + return INT2FIX(FL_TEST(obj, object_spec_FL_TEST_flag(flag))); +} + +static VALUE object_spec_rb_any_to_s(VALUE self, VALUE obj) { + return rb_any_to_s(obj); +} + +static VALUE so_attr_get(VALUE self, VALUE obj, VALUE attr) { + return rb_attr_get(obj, SYM2ID(attr)); +} + +static VALUE object_spec_rb_obj_instance_variables(VALUE self, VALUE obj) { + return rb_obj_instance_variables(obj); +} + +static VALUE so_check_array_type(VALUE self, VALUE ary) { + return rb_check_array_type(ary); +} + +static VALUE so_check_convert_type(VALUE self, VALUE obj, VALUE klass, VALUE method) { + return rb_check_convert_type(obj, T_ARRAY, RSTRING_PTR(klass), RSTRING_PTR(method)); +} + +static VALUE so_check_to_integer(VALUE self, VALUE obj, VALUE method) { + return rb_check_to_integer(obj, RSTRING_PTR(method)); +} + +static VALUE object_spec_rb_check_frozen(VALUE self, VALUE obj) { + rb_check_frozen(obj); + return Qnil; +} + +static VALUE so_check_string_type(VALUE self, VALUE str) { + return rb_check_string_type(str); +} + +static VALUE so_rbclassof(VALUE self, VALUE obj) { + return rb_class_of(obj); +} + +static VALUE so_convert_type(VALUE self, VALUE obj, VALUE klass, VALUE method) { + return rb_convert_type(obj, T_ARRAY, RSTRING_PTR(klass), RSTRING_PTR(method)); +} + +static VALUE object_spec_rb_extend_object(VALUE self, VALUE obj, VALUE mod) { + rb_extend_object(obj, mod); + return obj; +} + +static VALUE so_inspect(VALUE self, VALUE obj) { + return rb_inspect(obj); +} + +static VALUE so_rb_obj_alloc(VALUE self, VALUE klass) { + return rb_obj_alloc(klass); +} + +static VALUE so_rb_obj_dup(VALUE self, VALUE klass) { + return rb_obj_dup(klass); +} + +static VALUE so_rb_obj_call_init(VALUE self, VALUE object, + VALUE nargs, VALUE args) { + int c_nargs = FIX2INT(nargs); + VALUE *c_args = (VALUE*) alloca(sizeof(VALUE) * c_nargs); + int i; + + for (i = 0; i < c_nargs; i++) + c_args[i] = rb_ary_entry(args, i); + + rb_obj_call_init(object, c_nargs, c_args); + + return Qnil; +} + +static VALUE so_rb_obj_class(VALUE self, VALUE obj) { + return rb_obj_class(obj); +} + +static VALUE so_rbobjclassname(VALUE self, VALUE obj) { + return rb_str_new2(rb_obj_classname(obj)); +} + +static VALUE object_spec_rb_obj_freeze(VALUE self, VALUE obj) { + return rb_obj_freeze(obj); +} + +static VALUE object_spec_rb_obj_frozen_p(VALUE self, VALUE obj) { + return rb_obj_frozen_p(obj); +} + +static VALUE object_spec_rb_obj_id(VALUE self, VALUE obj) { + return rb_obj_id(obj); +} + +static VALUE so_instance_of(VALUE self, VALUE obj, VALUE klass) { + return rb_obj_is_instance_of(obj, klass); +} + +static VALUE so_kind_of(VALUE self, VALUE obj, VALUE klass) { + return rb_obj_is_kind_of(obj, klass); +} + +static VALUE object_specs_rb_obj_method_arity(VALUE self, VALUE obj, VALUE mid) { + return INT2FIX(rb_obj_method_arity(obj, SYM2ID(mid))); +} + +static VALUE object_specs_rb_obj_method(VALUE self, VALUE obj, VALUE method) { + return rb_obj_method(obj, method); +} + +static VALUE so_require(VALUE self) { + rb_require("fixtures/foo"); + return Qnil; +} + +static VALUE so_respond_to(VALUE self, VALUE obj, VALUE sym) { + return rb_respond_to(obj, SYM2ID(sym)) ? Qtrue : Qfalse; +} + +static VALUE so_obj_respond_to(VALUE self, VALUE obj, VALUE sym, VALUE priv) { + return rb_obj_respond_to(obj, SYM2ID(sym), priv == Qtrue ? 1 : 0) ? Qtrue : Qfalse; +} + +static VALUE object_spec_rb_method_boundp(VALUE self, VALUE obj, VALUE method, VALUE exclude_private) { + ID id = SYM2ID(method); + return rb_method_boundp(obj, id, exclude_private == Qtrue ? 1 : 0) ? Qtrue : Qfalse; +} + +static VALUE object_spec_rb_special_const_p(VALUE self, VALUE value) { + return rb_special_const_p(value); +} + +static VALUE so_to_id(VALUE self, VALUE obj) { + return ID2SYM(rb_to_id(obj)); +} + +static VALUE object_spec_RTEST(VALUE self, VALUE value) { + return RTEST(value) ? Qtrue : Qfalse; +} + +static VALUE so_check_type(VALUE self, VALUE obj, VALUE other) { + rb_check_type(obj, TYPE(other)); + return Qtrue; +} + +static VALUE so_is_type_nil(VALUE self, VALUE obj) { + if (TYPE(obj) == T_NIL) { + return Qtrue; + } + return Qfalse; +} + +static VALUE so_is_type_object(VALUE self, VALUE obj) { + if (TYPE(obj) == T_OBJECT) { + return Qtrue; + } + return Qfalse; +} + +static VALUE so_is_type_array(VALUE self, VALUE obj) { + if (TYPE(obj) == T_ARRAY) { + return Qtrue; + } + return Qfalse; +} + +static VALUE so_is_type_module(VALUE self, VALUE obj) { + if (TYPE(obj) == T_MODULE) { + return Qtrue; + } + return Qfalse; +} + +static VALUE so_is_type_class(VALUE self, VALUE obj) { + if (TYPE(obj) == T_CLASS) { + return Qtrue; + } + return Qfalse; +} + +static VALUE so_is_type_data(VALUE self, VALUE obj) { + if (TYPE(obj) == T_DATA) { + return Qtrue; + } + return Qfalse; +} + +static VALUE so_is_rb_type_p_nil(VALUE self, VALUE obj) { + if (rb_type_p(obj, T_NIL)) { + return Qtrue; + } + return Qfalse; +} + +static VALUE so_is_rb_type_p_object(VALUE self, VALUE obj) { + if (rb_type_p(obj, T_OBJECT)) { + return Qtrue; + } + return Qfalse; +} + +static VALUE so_is_rb_type_p_array(VALUE self, VALUE obj) { + if (rb_type_p(obj, T_ARRAY)) { + return Qtrue; + } + return Qfalse; +} + +static VALUE so_is_rb_type_p_module(VALUE self, VALUE obj) { + if (rb_type_p(obj, T_MODULE)) { + return Qtrue; + } + return Qfalse; +} + +static VALUE so_is_rb_type_p_class(VALUE self, VALUE obj) { + if (rb_type_p(obj, T_CLASS)) { + return Qtrue; + } + return Qfalse; +} + +static VALUE so_is_rb_type_p_data(VALUE self, VALUE obj) { + if (rb_type_p(obj, T_DATA)) { + return Qtrue; + } + return Qfalse; +} + +static VALUE so_is_rb_type_p_file(VALUE self, VALUE obj) { + if (rb_type_p(obj, T_FILE)) { + return Qtrue; + } + return Qfalse; +} + +static VALUE so_is_builtin_type_object(VALUE self, VALUE obj) { + if (BUILTIN_TYPE(obj) == T_OBJECT) { + return Qtrue; + } + return Qfalse; +} + +static VALUE so_is_builtin_type_array(VALUE self, VALUE obj) { + if (BUILTIN_TYPE(obj) == T_ARRAY) { + return Qtrue; + } + return Qfalse; +} + +static VALUE so_is_builtin_type_module(VALUE self, VALUE obj) { + if (BUILTIN_TYPE(obj) == T_MODULE) { + return Qtrue; + } + return Qfalse; +} + +static VALUE so_is_builtin_type_class(VALUE self, VALUE obj) { + if (BUILTIN_TYPE(obj) == T_CLASS) { + return Qtrue; + } + return Qfalse; +} + +static VALUE so_is_builtin_type_data(VALUE self, VALUE obj) { + if (BUILTIN_TYPE(obj) == T_DATA) { + return Qtrue; + } + return Qfalse; +} + +static VALUE object_spec_rb_to_int(VALUE self, VALUE obj) { + return rb_to_int(obj); +} + +static VALUE object_spec_rb_obj_instance_eval(VALUE self, VALUE obj) { + return rb_obj_instance_eval(0, NULL, obj); +} + +static VALUE object_spec_rb_iv_get(VALUE self, VALUE obj, VALUE name) { + return rb_iv_get(obj, RSTRING_PTR(name)); +} + +static VALUE object_spec_rb_iv_set(VALUE self, VALUE obj, VALUE name, VALUE value) { + return rb_iv_set(obj, RSTRING_PTR(name), value); +} + +static VALUE object_spec_rb_ivar_count(VALUE self, VALUE obj) { + return ULONG2NUM(rb_ivar_count(obj)); +} + +static VALUE object_spec_rb_ivar_get(VALUE self, VALUE obj, VALUE sym_name) { + return rb_ivar_get(obj, SYM2ID(sym_name)); +} + +static VALUE object_spec_rb_ivar_set(VALUE self, VALUE obj, VALUE sym_name, VALUE value) { + return rb_ivar_set(obj, SYM2ID(sym_name), value); +} + +static VALUE object_spec_rb_ivar_defined(VALUE self, VALUE obj, VALUE sym_name) { + return rb_ivar_defined(obj, SYM2ID(sym_name)); +} + +static VALUE object_spec_rb_copy_generic_ivar(VALUE self, VALUE clone, VALUE obj) { + rb_copy_generic_ivar(clone, obj); + return self; +} + +static VALUE object_spec_rb_free_generic_ivar(VALUE self, VALUE obj) { + rb_free_generic_ivar(obj); + return self; +} + +static VALUE object_spec_rb_equal(VALUE self, VALUE a, VALUE b) { + return rb_equal(a, b); +} + +static VALUE object_spec_rb_class_inherited_p(VALUE self, VALUE mod, VALUE arg) { + return rb_class_inherited_p(mod, arg); +} + +static int foreach_f(ID key, VALUE val, VALUE ary) { + rb_ary_push(ary, ID2SYM(key)); + rb_ary_push(ary, val); + return ST_CONTINUE; +} + +static VALUE object_spec_rb_ivar_foreach(VALUE self, VALUE obj) { + VALUE ary = rb_ary_new(); + rb_ivar_foreach(obj, foreach_f, ary); + return ary; +} + +static VALUE speced_allocator(VALUE klass) { + VALUE super = rb_class_get_superclass(klass); + VALUE instance = rb_get_alloc_func(super)(klass); + rb_iv_set(instance, "@from_custom_allocator", Qtrue); + return instance; +} + +static VALUE object_spec_rb_define_alloc_func(VALUE self, VALUE klass) { + rb_define_alloc_func(klass, speced_allocator); + return Qnil; +} + +static VALUE object_spec_rb_undef_alloc_func(VALUE self, VALUE klass) { + rb_undef_alloc_func(klass); + return Qnil; +} + +static VALUE object_spec_speced_allocator_p(VALUE self, VALUE klass) { + rb_alloc_func_t allocator = rb_get_alloc_func(klass); + return (allocator == speced_allocator) ? Qtrue : Qfalse; +} + +static VALUE object_spec_custom_alloc_func_p(VALUE self, VALUE klass) { + rb_alloc_func_t allocator = rb_get_alloc_func(klass); + return allocator ? Qtrue : Qfalse; +} + +static VALUE object_spec_redefine_frozen(VALUE self) { + // The purpose of this spec is to verify that `frozen?` + // and `RB_OBJ_FROZEN` do not mutually recurse infinitely. + if (RB_OBJ_FROZEN(self)) { + return Qtrue; + } + + return Qfalse; +} + +void Init_object_spec(void) { + VALUE cls = rb_define_class("CApiObjectSpecs", rb_cObject); + rb_define_method(cls, "FL_ABLE", object_spec_FL_ABLE, 1); + rb_define_method(cls, "FL_TEST", object_spec_FL_TEST, 2); + rb_define_method(cls, "rb_any_to_s", object_spec_rb_any_to_s, 1); + rb_define_method(cls, "rb_attr_get", so_attr_get, 2); + rb_define_method(cls, "rb_obj_instance_variables", object_spec_rb_obj_instance_variables, 1); + rb_define_method(cls, "rb_check_array_type", so_check_array_type, 1); + rb_define_method(cls, "rb_check_convert_type", so_check_convert_type, 3); + rb_define_method(cls, "rb_check_to_integer", so_check_to_integer, 2); + rb_define_method(cls, "rb_check_frozen", object_spec_rb_check_frozen, 1); + rb_define_method(cls, "rb_check_string_type", so_check_string_type, 1); + rb_define_method(cls, "rb_class_of", so_rbclassof, 1); + rb_define_method(cls, "rb_convert_type", so_convert_type, 3); + rb_define_method(cls, "rb_extend_object", object_spec_rb_extend_object, 2); + rb_define_method(cls, "rb_inspect", so_inspect, 1); + rb_define_method(cls, "rb_obj_alloc", so_rb_obj_alloc, 1); + rb_define_method(cls, "rb_obj_dup", so_rb_obj_dup, 1); + rb_define_method(cls, "rb_obj_call_init", so_rb_obj_call_init, 3); + rb_define_method(cls, "rb_obj_class", so_rb_obj_class, 1); + rb_define_method(cls, "rb_obj_classname", so_rbobjclassname, 1); + rb_define_method(cls, "rb_obj_freeze", object_spec_rb_obj_freeze, 1); + rb_define_method(cls, "rb_obj_frozen_p", object_spec_rb_obj_frozen_p, 1); + rb_define_method(cls, "rb_obj_id", object_spec_rb_obj_id, 1); + rb_define_method(cls, "rb_obj_is_instance_of", so_instance_of, 2); + rb_define_method(cls, "rb_obj_is_kind_of", so_kind_of, 2); + rb_define_method(cls, "rb_obj_method_arity", object_specs_rb_obj_method_arity, 2); + rb_define_method(cls, "rb_obj_method", object_specs_rb_obj_method, 2); + rb_define_method(cls, "rb_require", so_require, 0); + rb_define_method(cls, "rb_respond_to", so_respond_to, 2); + rb_define_method(cls, "rb_method_boundp", object_spec_rb_method_boundp, 3); + rb_define_method(cls, "rb_obj_respond_to", so_obj_respond_to, 3); + rb_define_method(cls, "rb_special_const_p", object_spec_rb_special_const_p, 1); + rb_define_method(cls, "rb_to_id", so_to_id, 1); + rb_define_method(cls, "RTEST", object_spec_RTEST, 1); + rb_define_method(cls, "rb_check_type", so_check_type, 2); + rb_define_method(cls, "rb_is_type_nil", so_is_type_nil, 1); + rb_define_method(cls, "rb_is_type_object", so_is_type_object, 1); + rb_define_method(cls, "rb_is_type_array", so_is_type_array, 1); + rb_define_method(cls, "rb_is_type_module", so_is_type_module, 1); + rb_define_method(cls, "rb_is_type_class", so_is_type_class, 1); + rb_define_method(cls, "rb_is_type_data", so_is_type_data, 1); + rb_define_method(cls, "rb_is_rb_type_p_nil", so_is_rb_type_p_nil, 1); + rb_define_method(cls, "rb_is_rb_type_p_object", so_is_rb_type_p_object, 1); + rb_define_method(cls, "rb_is_rb_type_p_array", so_is_rb_type_p_array, 1); + rb_define_method(cls, "rb_is_rb_type_p_module", so_is_rb_type_p_module, 1); + rb_define_method(cls, "rb_is_rb_type_p_class", so_is_rb_type_p_class, 1); + rb_define_method(cls, "rb_is_rb_type_p_data", so_is_rb_type_p_data, 1); + rb_define_method(cls, "rb_is_rb_type_p_file", so_is_rb_type_p_file, 1); + rb_define_method(cls, "rb_is_builtin_type_object", so_is_builtin_type_object, 1); + rb_define_method(cls, "rb_is_builtin_type_array", so_is_builtin_type_array, 1); + rb_define_method(cls, "rb_is_builtin_type_module", so_is_builtin_type_module, 1); + rb_define_method(cls, "rb_is_builtin_type_class", so_is_builtin_type_class, 1); + rb_define_method(cls, "rb_is_builtin_type_data", so_is_builtin_type_data, 1); + rb_define_method(cls, "rb_to_int", object_spec_rb_to_int, 1); + rb_define_method(cls, "rb_equal", object_spec_rb_equal, 2); + rb_define_method(cls, "rb_class_inherited_p", object_spec_rb_class_inherited_p, 2); + rb_define_method(cls, "rb_obj_instance_eval", object_spec_rb_obj_instance_eval, 1); + rb_define_method(cls, "rb_iv_get", object_spec_rb_iv_get, 2); + rb_define_method(cls, "rb_iv_set", object_spec_rb_iv_set, 3); + rb_define_method(cls, "rb_ivar_count", object_spec_rb_ivar_count, 1); + rb_define_method(cls, "rb_ivar_get", object_spec_rb_ivar_get, 2); + rb_define_method(cls, "rb_ivar_set", object_spec_rb_ivar_set, 3); + rb_define_method(cls, "rb_ivar_defined", object_spec_rb_ivar_defined, 2); + rb_define_method(cls, "rb_copy_generic_ivar", object_spec_rb_copy_generic_ivar, 2); + rb_define_method(cls, "rb_free_generic_ivar", object_spec_rb_free_generic_ivar, 1); + rb_define_method(cls, "rb_define_alloc_func", object_spec_rb_define_alloc_func, 1); + rb_define_method(cls, "rb_undef_alloc_func", object_spec_rb_undef_alloc_func, 1); + rb_define_method(cls, "speced_allocator?", object_spec_speced_allocator_p, 1); + rb_define_method(cls, "custom_alloc_func?", object_spec_custom_alloc_func_p, 1); + rb_define_method(cls, "not_implemented_method", rb_f_notimplement, -1); + rb_define_method(cls, "rb_ivar_foreach", object_spec_rb_ivar_foreach, 1); + + cls = rb_define_class("CApiObjectRedefinitionSpecs", rb_cObject); + rb_define_method(cls, "frozen?", object_spec_redefine_frozen, 0); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/proc_spec.c b/spec/ruby/optional/capi/ext/proc_spec.c new file mode 100644 index 0000000000..b7cd5d6262 --- /dev/null +++ b/spec/ruby/optional/capi/ext/proc_spec.c @@ -0,0 +1,147 @@ +#include "ruby.h" +#include "rubyspec.h" + +#include <string.h> + +#ifdef __cplusplus +extern "C" { +#endif + +VALUE proc_spec_rb_proc_new_function(RB_BLOCK_CALL_FUNC_ARGLIST(args, dummy)) { + return rb_funcall(args, rb_intern("inspect"), 0); +} + +VALUE proc_spec_rb_proc_new_function_arg(VALUE arg, VALUE callback_arg, int argc, const VALUE *argv, VALUE blockarg) { + return arg; +} + +VALUE proc_spec_rb_proc_new_function_argc(VALUE arg, VALUE callback_arg, int argc, const VALUE *argv, VALUE blockarg) { + return INT2FIX(argc); +} + +VALUE proc_spec_rb_proc_new_function_argv_n(VALUE arg, VALUE callback_arg, int argc, const VALUE *argv, VALUE blockarg) { + int n = FIX2INT(arg); + if (n < argc) { + return argv[n]; + } else { + rb_exc_raise(rb_exc_new2(rb_eArgError, "Arg index out of bounds.")); + } +} + +VALUE proc_spec_rb_proc_new_function_callback_arg(VALUE arg, VALUE callback_arg, int argc, const VALUE *argv, VALUE blockarg) { + return callback_arg; +} + +VALUE proc_spec_rb_proc_new_function_blockarg(VALUE arg, VALUE callback_arg, int argc, const VALUE *argv, VALUE blockarg) { + return blockarg; +} + +VALUE proc_spec_rb_proc_new_function_block_given_p(VALUE arg, VALUE callback_arg, int argc, const VALUE *argv, VALUE blockarg) { + return rb_block_given_p() ? Qtrue : Qfalse; +} + +VALUE proc_spec_rb_proc_new(VALUE self) { + return rb_proc_new(proc_spec_rb_proc_new_function, Qnil); +} + +VALUE proc_spec_rb_proc_new_arg(VALUE self) { + return rb_proc_new(proc_spec_rb_proc_new_function_arg, Qnil); +} + +VALUE proc_spec_rb_proc_new_argc(VALUE self) { + return rb_proc_new(proc_spec_rb_proc_new_function_argc, Qnil); +} + +VALUE proc_spec_rb_proc_new_argv_n(VALUE self) { + return rb_proc_new(proc_spec_rb_proc_new_function_argv_n, Qnil); +} + +VALUE proc_spec_rb_proc_new_callback_arg(VALUE self, VALUE arg) { + return rb_proc_new(proc_spec_rb_proc_new_function_callback_arg, arg); +} + +VALUE proc_spec_rb_proc_new_blockarg(VALUE self) { + return rb_proc_new(proc_spec_rb_proc_new_function_blockarg, Qnil); +} + +VALUE proc_spec_rb_proc_new_block_given_p(VALUE self) { + return rb_proc_new(proc_spec_rb_proc_new_function_block_given_p, Qnil); +} + +VALUE proc_spec_rb_proc_arity(VALUE self, VALUE prc) { + return INT2FIX(rb_proc_arity(prc)); +} + +VALUE proc_spec_rb_proc_call(VALUE self, VALUE prc, VALUE args) { + return rb_proc_call(prc, args); +} + +VALUE proc_spec_rb_proc_call_kw(VALUE self, VALUE prc, VALUE args) { + return rb_proc_call_kw(prc, args, RB_PASS_KEYWORDS); +} + +VALUE proc_spec_rb_proc_call_with_block(VALUE self, VALUE prc, VALUE args, VALUE block) { + return rb_proc_call_with_block(prc, RARRAY_LENINT(args), RARRAY_PTR(args), block); +} + +static VALUE proc_spec_rb_proc_call_with_block_kw(VALUE self, VALUE prc, VALUE args, VALUE block) { + return rb_proc_call_with_block_kw(prc, RARRAY_LENINT(args), RARRAY_PTR(args), block, RB_PASS_KEYWORDS); +} + +VALUE proc_spec_rb_obj_is_proc(VALUE self, VALUE prc) { + return rb_obj_is_proc(prc); +} + +/* This helper is not strictly necessary but reflects the code in wxRuby that + * originally exposed issues with this Proc.new behavior. + */ +VALUE proc_spec_rb_Proc_new_helper(void) { + return rb_funcall(rb_cProc, rb_intern("new"), 0); +} + +VALUE proc_spec_rb_Proc_new(VALUE self, VALUE scenario) { + switch(FIX2INT(scenario)) { + case 0: + return proc_spec_rb_Proc_new_helper(); + case 1: + rb_funcall(self, rb_intern("call_nothing"), 0); + return proc_spec_rb_Proc_new_helper(); + case 2: + return rb_funcall(self, rb_intern("call_Proc_new"), 0); + case 3: + return rb_funcall(self, rb_intern("call_rb_Proc_new"), 0); + case 4: + return rb_funcall(self, rb_intern("call_rb_Proc_new_with_block"), 0); + case 5: + rb_funcall(self, rb_intern("call_rb_Proc_new_with_block"), 0); + return proc_spec_rb_Proc_new_helper(); + case 6: + return rb_funcall(self, rb_intern("call_block_given?"), 0); + default: + rb_raise(rb_eException, "invalid scenario"); + } + + return Qnil; +} + +void Init_proc_spec(void) { + VALUE cls = rb_define_class("CApiProcSpecs", rb_cObject); + rb_define_method(cls, "rb_proc_new", proc_spec_rb_proc_new, 0); + rb_define_method(cls, "rb_proc_new_arg", proc_spec_rb_proc_new_arg, 0); + rb_define_method(cls, "rb_proc_new_argc", proc_spec_rb_proc_new_argc, 0); + rb_define_method(cls, "rb_proc_new_argv_n", proc_spec_rb_proc_new_argv_n, 0); + rb_define_method(cls, "rb_proc_new_callback_arg", proc_spec_rb_proc_new_callback_arg, 1); + rb_define_method(cls, "rb_proc_new_blockarg", proc_spec_rb_proc_new_blockarg, 0); + rb_define_method(cls, "rb_proc_new_block_given_p", proc_spec_rb_proc_new_block_given_p, 0); + rb_define_method(cls, "rb_proc_arity", proc_spec_rb_proc_arity, 1); + rb_define_method(cls, "rb_proc_call", proc_spec_rb_proc_call, 2); + rb_define_method(cls, "rb_proc_call_kw", proc_spec_rb_proc_call_kw, 2); + rb_define_method(cls, "rb_proc_call_with_block", proc_spec_rb_proc_call_with_block, 3); + rb_define_method(cls, "rb_proc_call_with_block_kw", proc_spec_rb_proc_call_with_block_kw, 3); + rb_define_method(cls, "rb_Proc_new", proc_spec_rb_Proc_new, 1); + rb_define_method(cls, "rb_obj_is_proc", proc_spec_rb_obj_is_proc, 1); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/range_spec.c b/spec/ruby/optional/capi/ext/range_spec.c new file mode 100644 index 0000000000..9faed3e5ee --- /dev/null +++ b/spec/ruby/optional/capi/ext/range_spec.c @@ -0,0 +1,90 @@ +#include "ruby.h" +#include "rubyspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +VALUE range_spec_rb_range_new(int argc, VALUE* argv, VALUE self) { + int exclude_end = 0; + if (argc == 3) { + exclude_end = RTEST(argv[2]); + } + return rb_range_new(argv[0], argv[1], exclude_end); +} + +VALUE range_spec_rb_range_values(VALUE self, VALUE range) { + VALUE beg; + VALUE end; + int excl; + VALUE ary = rb_ary_new(); + rb_range_values(range, &beg, &end, &excl); + rb_ary_store(ary, 0, beg); + rb_ary_store(ary, 1, end); + rb_ary_store(ary, 2, excl ? Qtrue : Qfalse); + return ary; +} + +VALUE range_spec_rb_range_beg_len(VALUE self, VALUE range, VALUE lenv, VALUE errv) { + long begp = 0; + long lenp = 0; + long len = FIX2LONG(lenv); + int err = FIX2INT(errv); + VALUE ary = rb_ary_new(); + VALUE res = rb_range_beg_len(range, &begp, &lenp, len, err); + rb_ary_store(ary, 0, LONG2FIX(begp)); + rb_ary_store(ary, 1, LONG2FIX(lenp)); + rb_ary_store(ary, 2, res); + return ary; +} + +VALUE range_spec_rb_arithmetic_sequence_extract(VALUE self, VALUE object) { + VALUE ary = rb_ary_new(); + rb_arithmetic_sequence_components_t components; + + int status = rb_arithmetic_sequence_extract(object, &components); + + if (!status) { + rb_ary_store(ary, 0, LONG2FIX(status)); + return ary; + } + + rb_ary_store(ary, 0, LONG2FIX(status)); + rb_ary_store(ary, 1, components.begin); + rb_ary_store(ary, 2, components.end); + rb_ary_store(ary, 3, components.step); + rb_ary_store(ary, 4, components.exclude_end ? Qtrue : Qfalse); + return ary; +} + +VALUE range_spec_rb_arithmetic_sequence_beg_len_step(VALUE self, VALUE aseq, VALUE lenv, VALUE errv) { + long begp = 0; + long lenp = 0; + long stepp = 0; + + long len = FIX2LONG(lenv); + int err = FIX2INT(errv); + + VALUE success = rb_arithmetic_sequence_beg_len_step(aseq, &begp, &lenp, &stepp, len, err); + + VALUE ary = rb_ary_new(); + rb_ary_store(ary, 0, success); + rb_ary_store(ary, 1, LONG2FIX(begp)); + rb_ary_store(ary, 2, LONG2FIX(lenp)); + rb_ary_store(ary, 3, LONG2FIX(stepp)); + + return ary; +} + +void Init_range_spec(void) { + VALUE cls = rb_define_class("CApiRangeSpecs", rb_cObject); + rb_define_method(cls, "rb_range_new", range_spec_rb_range_new, -1); + rb_define_method(cls, "rb_range_values", range_spec_rb_range_values, 1); + rb_define_method(cls, "rb_range_beg_len", range_spec_rb_range_beg_len, 3); + rb_define_method(cls, "rb_arithmetic_sequence_extract", range_spec_rb_arithmetic_sequence_extract, 1); + rb_define_method(cls, "rb_arithmetic_sequence_beg_len_step", range_spec_rb_arithmetic_sequence_beg_len_step, 3); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/rational_spec.c b/spec/ruby/optional/capi/ext/rational_spec.c new file mode 100644 index 0000000000..6273af68c5 --- /dev/null +++ b/spec/ruby/optional/capi/ext/rational_spec.c @@ -0,0 +1,54 @@ +#include "ruby.h" +#include "rubyspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static VALUE rational_spec_rb_Rational(VALUE self, VALUE num, VALUE den) { + return rb_Rational(num, den); +} + +static VALUE rational_spec_rb_Rational1(VALUE self, VALUE num) { + return rb_Rational1(num); +} + +static VALUE rational_spec_rb_Rational2(VALUE self, VALUE num, VALUE den) { + return rb_Rational2(num, den); +} + +static VALUE rational_spec_rb_rational_new(VALUE self, VALUE num, VALUE den) { + return rb_rational_new(num, den); +} + +static VALUE rational_spec_rb_rational_new1(VALUE self, VALUE num) { + return rb_rational_new1(num); +} + +static VALUE rational_spec_rb_rational_new2(VALUE self, VALUE num, VALUE den) { + return rb_rational_new2(num, den); +} + +static VALUE rational_spec_rb_rational_num(VALUE self, VALUE rational) { + return rb_rational_num(rational); +} + +static VALUE rational_spec_rb_rational_den(VALUE self, VALUE rational) { + return rb_rational_den(rational); +} + +void Init_rational_spec(void) { + VALUE cls = rb_define_class("CApiRationalSpecs", rb_cObject); + rb_define_method(cls, "rb_Rational", rational_spec_rb_Rational, 2); + rb_define_method(cls, "rb_Rational1", rational_spec_rb_Rational1, 1); + rb_define_method(cls, "rb_Rational2", rational_spec_rb_Rational2, 2); + rb_define_method(cls, "rb_rational_new", rational_spec_rb_rational_new, 2); + rb_define_method(cls, "rb_rational_new1", rational_spec_rb_rational_new1, 1); + rb_define_method(cls, "rb_rational_new2", rational_spec_rb_rational_new2, 2); + rb_define_method(cls, "rb_rational_num", rational_spec_rb_rational_num, 1); + rb_define_method(cls, "rb_rational_den", rational_spec_rb_rational_den, 1); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/rbasic_spec.c b/spec/ruby/optional/capi/ext/rbasic_spec.c new file mode 100644 index 0000000000..5a95b92804 --- /dev/null +++ b/spec/ruby/optional/capi/ext/rbasic_spec.c @@ -0,0 +1,104 @@ +#include "ruby.h" +#include "rubyspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef RBASIC_FLAGS +#define RBASIC_FLAGS(obj) (RBASIC(obj)->flags) +#endif + +#ifndef RBASIC_SET_FLAGS +#define RBASIC_SET_FLAGS(obj, flags_to_set) (RBASIC(obj)->flags = flags_to_set) +#endif + +#ifndef FL_SHAREABLE +static const VALUE VISIBLE_BITS = FL_TAINT | FL_FREEZE; +static const VALUE DATA_VISIBLE_BITS = FL_TAINT | FL_FREEZE | ~(FL_USER0 - 1); +#else +static const VALUE VISIBLE_BITS = FL_FREEZE; +static const VALUE DATA_VISIBLE_BITS = FL_FREEZE | ~(FL_USER0 - 1); +#endif + +#if SIZEOF_VALUE == SIZEOF_LONG +#define VALUE2NUM(v) ULONG2NUM(v) +#define NUM2VALUE(n) NUM2ULONG(n) +#elif SIZEOF_VALUE == SIZEOF_LONG_LONG +#define VALUE2NUM(v) ULL2NUM(v) +#define NUM2VALUE(n) NUM2ULL(n) +#else +#error "unsupported" +#endif + +VALUE rbasic_spec_freeze_flag(VALUE self) { + return VALUE2NUM(RUBY_FL_FREEZE); +} + +static VALUE spec_get_flags(VALUE obj, VALUE visible_bits) { + VALUE flags = RB_FL_TEST(obj, visible_bits); + return VALUE2NUM(flags); +} + +static VALUE spec_set_flags(VALUE obj, VALUE flags, VALUE visible_bits) { + flags &= visible_bits; + + // Could also be done like: + // RB_FL_UNSET(obj, visible_bits); + // RB_FL_SET(obj, flags); + // But that seems rather indirect + RBASIC_SET_FLAGS(obj, (RBASIC_FLAGS(obj) & ~visible_bits) | flags); + + return VALUE2NUM(flags); +} + +static VALUE rbasic_spec_get_flags(VALUE self, VALUE obj) { + return spec_get_flags(obj, VISIBLE_BITS); +} + +static VALUE rbasic_spec_set_flags(VALUE self, VALUE obj, VALUE flags) { + return spec_set_flags(obj, NUM2VALUE(flags), VISIBLE_BITS); +} + +static VALUE rbasic_spec_copy_flags(VALUE self, VALUE to, VALUE from) { + return spec_set_flags(to, RBASIC_FLAGS(from), VISIBLE_BITS); +} + +static VALUE rbasic_spec_get_klass(VALUE self, VALUE obj) { + return RBASIC_CLASS(obj); +} + +static VALUE rbasic_rdata_spec_get_flags(VALUE self, VALUE structure) { + return spec_get_flags(structure, DATA_VISIBLE_BITS); +} + +static VALUE rbasic_rdata_spec_set_flags(VALUE self, VALUE structure, VALUE flags) { + return spec_set_flags(structure, NUM2VALUE(flags), DATA_VISIBLE_BITS); +} + +static VALUE rbasic_rdata_spec_copy_flags(VALUE self, VALUE to, VALUE from) { + return spec_set_flags(to, RBASIC_FLAGS(from), DATA_VISIBLE_BITS); +} + +static VALUE rbasic_rdata_spec_get_klass(VALUE self, VALUE structure) { + return RBASIC_CLASS(structure); +} + +void Init_rbasic_spec(void) { + VALUE cls = rb_define_class("CApiRBasicSpecs", rb_cObject); + rb_define_method(cls, "freeze_flag", rbasic_spec_freeze_flag, 0); + rb_define_method(cls, "get_flags", rbasic_spec_get_flags, 1); + rb_define_method(cls, "set_flags", rbasic_spec_set_flags, 2); + rb_define_method(cls, "copy_flags", rbasic_spec_copy_flags, 2); + rb_define_method(cls, "get_klass", rbasic_spec_get_klass, 1); + + cls = rb_define_class("CApiRBasicRDataSpecs", rb_cObject); + rb_define_method(cls, "get_flags", rbasic_rdata_spec_get_flags, 1); + rb_define_method(cls, "set_flags", rbasic_rdata_spec_set_flags, 2); + rb_define_method(cls, "copy_flags", rbasic_rdata_spec_copy_flags, 2); + rb_define_method(cls, "get_klass", rbasic_rdata_spec_get_klass, 1); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/regexp_spec.c b/spec/ruby/optional/capi/ext/regexp_spec.c new file mode 100644 index 0000000000..9de7982b50 --- /dev/null +++ b/spec/ruby/optional/capi/ext/regexp_spec.c @@ -0,0 +1,74 @@ +#include "ruby.h" +#include "rubyspec.h" + +#include "ruby/re.h" + +#include <string.h> + +#ifdef __cplusplus +extern "C" { +#endif + +VALUE regexp_spec_re(VALUE self, VALUE str, VALUE options) { + char *cstr = StringValueCStr(str); + int opts = FIX2INT(options); + return rb_reg_new(cstr, strlen(cstr), opts); +} + +VALUE regexp_spec_reg_1st_match(VALUE self, VALUE md) { + return rb_reg_nth_match(1, md); +} + +VALUE regexp_spec_rb_reg_options(VALUE self, VALUE regexp) { + return INT2FIX(rb_reg_options(regexp)); +} + +VALUE regexp_spec_rb_reg_regcomp(VALUE self, VALUE str) { + return rb_reg_regcomp(str); +} + +VALUE regexp_spec_reg_match(VALUE self, VALUE re, VALUE str) { + return rb_reg_match(re, str); +} + +VALUE regexp_spec_backref_get(VALUE self) { + return rb_backref_get(); +} + +static VALUE regexp_spec_backref_set(VALUE self, VALUE backref) { + rb_backref_set(backref); + return Qnil; +} + +VALUE regexp_spec_reg_match_backref_get(VALUE self, VALUE re, VALUE str) { + rb_reg_match(re, str); + return rb_backref_get(); +} + +VALUE regexp_spec_match(VALUE self, VALUE regexp, VALUE str) { + return rb_funcall(regexp, rb_intern("match"), 1, str); +} + +VALUE regexp_spec_memcicmp(VALUE self, VALUE str1, VALUE str2) { + long l1 = RSTRING_LEN(str1); + long l2 = RSTRING_LEN(str2); + return INT2FIX(rb_memcicmp(RSTRING_PTR(str1), RSTRING_PTR(str2), l1 < l2 ? l1 : l2)); +} + +void Init_regexp_spec(void) { + VALUE cls = rb_define_class("CApiRegexpSpecs", rb_cObject); + rb_define_method(cls, "match", regexp_spec_match, 2); + rb_define_method(cls, "a_re", regexp_spec_re, 2); + rb_define_method(cls, "a_re_1st_match", regexp_spec_reg_1st_match, 1); + rb_define_method(cls, "rb_reg_match", regexp_spec_reg_match, 2); + rb_define_method(cls, "rb_backref_get", regexp_spec_backref_get, 0); + rb_define_method(cls, "rb_backref_set", regexp_spec_backref_set, 1); + rb_define_method(cls, "rb_reg_match_backref_get", regexp_spec_reg_match_backref_get, 2); + rb_define_method(cls, "rb_reg_options", regexp_spec_rb_reg_options, 1); + rb_define_method(cls, "rb_reg_regcomp", regexp_spec_rb_reg_regcomp, 1); + rb_define_method(cls, "rb_memcicmp", regexp_spec_memcicmp, 2); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/rubyspec.h b/spec/ruby/optional/capi/ext/rubyspec.h new file mode 100644 index 0000000000..6c4bea5da0 --- /dev/null +++ b/spec/ruby/optional/capi/ext/rubyspec.h @@ -0,0 +1,50 @@ +#ifndef RUBYSPEC_H +#define RUBYSPEC_H + +/* Define convenience macros similar to the mspec + * guards to assist with version incompatibilities. */ + +#include <ruby.h> +#include <ruby/version.h> + +/* copied from ext/-test-/cxxanyargs/cxxanyargs.cpp */ +#if 0 /* Ignore deprecation warnings */ + +#elif defined(_MSC_VER) +#pragma warning(disable : 4996) + +#elif defined(__INTEL_COMPILER) +#pragma warning(disable : 1786) + +#elif defined(__clang__) +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +#elif defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + +#elif defined(__SUNPRO_CC) +#pragma error_messages (off,symdeprecated) + +#else +// :FIXME: improve here for your compiler. + +#endif + +#define RUBY_VERSION_BEFORE(major,minor) \ + ((RUBY_API_VERSION_MAJOR < (major)) || \ + (RUBY_API_VERSION_MAJOR == (major) && RUBY_API_VERSION_MINOR < (minor))) +#define RUBY_VERSION_SINCE(major,minor) (!RUBY_VERSION_BEFORE(major, minor)) + +#if RUBY_VERSION_SINCE(4, 0) +#define RUBY_VERSION_IS_4_0 +#endif + +#if RUBY_VERSION_SINCE(3, 4) +#define RUBY_VERSION_IS_3_4 +#endif + +#if RUBY_VERSION_SINCE(3, 3) +#define RUBY_VERSION_IS_3_3 +#endif + +#endif diff --git a/spec/ruby/optional/capi/ext/set_spec.c b/spec/ruby/optional/capi/ext/set_spec.c new file mode 100644 index 0000000000..11a271b361 --- /dev/null +++ b/spec/ruby/optional/capi/ext/set_spec.c @@ -0,0 +1,65 @@ +#include "ruby.h" +#include "rubyspec.h" + +#ifdef RUBY_VERSION_IS_4_0 +#ifdef __cplusplus +extern "C" { +#endif + +#define RBOOL(x) ((x) ? Qtrue : Qfalse) + +int yield_element_and_arg(VALUE element, VALUE arg) { + return RTEST(rb_yield_values(2, element, arg)) ? ST_CONTINUE : ST_STOP; +} + +VALUE set_spec_rb_set_foreach(VALUE self, VALUE set, VALUE arg) { + rb_set_foreach(set, yield_element_and_arg, arg); + return Qnil; +} + +VALUE set_spec_rb_set_new(VALUE self) { + return rb_set_new(); +} + +VALUE set_spec_rb_set_new_capa(VALUE self, VALUE capa) { + return rb_set_new_capa(NUM2INT(capa)); +} + +VALUE set_spec_rb_set_lookup(VALUE self, VALUE set, VALUE element) { + return RBOOL(rb_set_lookup(set, element)); +} + +VALUE set_spec_rb_set_add(VALUE self, VALUE set, VALUE element) { + return RBOOL(rb_set_add(set, element)); +} + +VALUE set_spec_rb_set_clear(VALUE self, VALUE set) { + return rb_set_clear(set); +} + +VALUE set_spec_rb_set_delete(VALUE self, VALUE set, VALUE element) { + return RBOOL(rb_set_delete(set, element)); +} + +VALUE set_spec_rb_set_size(VALUE self, VALUE set) { + return SIZET2NUM(rb_set_size(set)); +} + +void Init_set_spec(void) { + VALUE cls = rb_define_class("CApiSetSpecs", rb_cObject); + + rb_define_method(cls, "rb_set_foreach", set_spec_rb_set_foreach, 2); + rb_define_method(cls, "rb_set_new", set_spec_rb_set_new, 0); + rb_define_method(cls, "rb_set_new_capa", set_spec_rb_set_new_capa, 1); + rb_define_method(cls, "rb_set_lookup", set_spec_rb_set_lookup, 2); + rb_define_method(cls, "rb_set_add", set_spec_rb_set_add, 2); + rb_define_method(cls, "rb_set_clear", set_spec_rb_set_clear, 1); + rb_define_method(cls, "rb_set_delete", set_spec_rb_set_delete, 2); + rb_define_method(cls, "rb_set_size", set_spec_rb_set_size, 1); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/spec/ruby/optional/capi/ext/st_spec.c b/spec/ruby/optional/capi/ext/st_spec.c new file mode 100644 index 0000000000..0fb5b5dc2d --- /dev/null +++ b/spec/ruby/optional/capi/ext/st_spec.c @@ -0,0 +1,83 @@ +#include "ruby.h" +#include "rubyspec.h" + +#include <string.h> +#include <stdarg.h> + +#include <ruby/st.h> + +#ifdef __cplusplus +extern "C" { +#endif + + +#if SIZEOF_LONG == SIZEOF_VOIDP +# define ST2NUM(x) ULONG2NUM(x) +#else +# define ST2NUM(x) ULL2NUM(x) +#endif + +VALUE st_spec_st_init_numtable(VALUE self) { + st_table *tbl = st_init_numtable(); + st_index_t entries = tbl->num_entries; + st_free_table(tbl); + return ST2NUM(entries); +} + +VALUE st_spec_st_init_numtable_with_size(VALUE self) { + st_table *tbl = st_init_numtable_with_size(128); + st_index_t entries = tbl->num_entries; + st_free_table(tbl); + return ST2NUM(entries); +} + +VALUE st_spec_st_insert(VALUE self) { + st_index_t entries; + st_table *tbl = st_init_numtable_with_size(128); + st_insert(tbl, 1, 1); + entries = tbl->num_entries; + st_free_table(tbl); + return ST2NUM(entries); +} + +static int sum(st_data_t key, st_data_t value, st_data_t arg) { + *(int*)arg += (int)value; + return ST_CONTINUE; +} + +VALUE st_spec_st_foreach(VALUE self) { + int total = 0; + st_table *tbl = st_init_numtable_with_size(128); + st_insert(tbl, 1, 3); + st_insert(tbl, 2, 4); + st_foreach(tbl, sum, (st_data_t)&total); + st_free_table(tbl); + return INT2FIX(total); +} + +VALUE st_spec_st_lookup(VALUE self) { + st_data_t result = (st_data_t)0; + st_table *tbl = st_init_numtable_with_size(128); + st_insert(tbl, 7, 42); + st_insert(tbl, 2, 4); + st_lookup(tbl, (st_data_t)7, &result); + st_free_table(tbl); +#if SIZEOF_LONG == SIZEOF_VOIDP + return ULONG2NUM(result); +#else + return ULL2NUM(result); +#endif +} + +void Init_st_spec(void) { + VALUE cls = rb_define_class("CApiStSpecs", rb_cObject); + rb_define_method(cls, "st_init_numtable", st_spec_st_init_numtable, 0); + rb_define_method(cls, "st_init_numtable_with_size", st_spec_st_init_numtable_with_size, 0); + rb_define_method(cls, "st_insert", st_spec_st_insert, 0); + rb_define_method(cls, "st_foreach", st_spec_st_foreach, 0); + rb_define_method(cls, "st_lookup", st_spec_st_lookup, 0); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/string_spec.c b/spec/ruby/optional/capi/ext/string_spec.c new file mode 100644 index 0000000000..094013e049 --- /dev/null +++ b/spec/ruby/optional/capi/ext/string_spec.c @@ -0,0 +1,688 @@ +#include "ruby.h" +#include "rubyspec.h" + +#include <fcntl.h> +#include <string.h> +#include <stdarg.h> +#include <errno.h> + +#include "ruby/encoding.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Make sure the RSTRING_PTR and the bytes are in native memory. + * On TruffleRuby RSTRING_PTR and the bytes remain in managed memory + * until they must be written to native memory. + * In some specs we want to test using the native memory. */ +#ifndef NATIVE_RSTRING_PTR +#define NATIVE_RSTRING_PTR(str) RSTRING_PTR(str) +#endif + +VALUE string_spec_rb_cstr2inum(VALUE self, VALUE str, VALUE inum) { + int num = FIX2INT(inum); + return rb_cstr2inum(RSTRING_PTR(str), num); +} + +static VALUE string_spec_rb_cstr_to_inum(VALUE self, VALUE str, VALUE inum, VALUE badcheck) { + int num = FIX2INT(inum); + return rb_cstr_to_inum(RSTRING_PTR(str), num, RTEST(badcheck)); +} + +VALUE string_spec_rb_str2inum(VALUE self, VALUE str, VALUE inum) { + int num = FIX2INT(inum); + return rb_str2inum(str, num); +} + +VALUE string_spec_rb_str_append(VALUE self, VALUE str, VALUE str2) { + return rb_str_append(str, str2); +} + +VALUE string_spec_rb_str_set_len(VALUE self, VALUE str, VALUE len) { + rb_str_set_len(str, NUM2LONG(len)); + + return str; +} + +VALUE string_spec_rb_str_set_len_RSTRING_LEN(VALUE self, VALUE str, VALUE len) { + rb_str_set_len(str, NUM2LONG(len)); + + return INT2FIX(RSTRING_LEN(str)); +} + +VALUE string_spec_rb_str_buf_new(VALUE self, VALUE len, VALUE str) { + VALUE buf; + + buf = rb_str_buf_new(NUM2LONG(len)); + + if (RTEST(str)) { + snprintf(RSTRING_PTR(buf), NUM2LONG(len), "%s", RSTRING_PTR(str)); + } + + return buf; +} + +VALUE string_spec_rb_str_capacity(VALUE self, VALUE str) { + return SIZET2NUM(rb_str_capacity(str)); +} + +VALUE string_spec_rb_str_buf_new2(VALUE self) { + return rb_str_buf_new2("hello\0invisible"); +} + +VALUE string_spec_rb_str_tmp_new(VALUE self, VALUE len) { + VALUE str = rb_str_tmp_new(NUM2LONG(len)); + rb_obj_reveal(str, rb_cString); + return str; +} + +VALUE string_spec_rb_str_tmp_new_klass(VALUE self, VALUE len) { + return RBASIC_CLASS(rb_str_tmp_new(NUM2LONG(len))); +} + +VALUE string_spec_rb_str_buf_append(VALUE self, VALUE str, VALUE two) { + return rb_str_buf_append(str, two); +} + +VALUE string_spec_rb_str_buf_cat(VALUE self, VALUE str) { + const char *question_mark = "?"; + rb_str_buf_cat(str, question_mark, strlen(question_mark)); + return str; +} + +VALUE string_spec_rb_enc_str_buf_cat(VALUE self, VALUE str, VALUE other, VALUE encoding) { + char *cstr = StringValueCStr(other); + rb_encoding* enc = rb_to_encoding(encoding); + return rb_enc_str_buf_cat(str, cstr, strlen(cstr), enc); +} + +VALUE string_spec_rb_str_cat(VALUE self, VALUE str) { + return rb_str_cat(str, "?", 1); +} + +VALUE string_spec_rb_str_cat2(VALUE self, VALUE str) { + return rb_str_cat2(str, "?"); +} + +VALUE string_spec_rb_str_cat_cstr(VALUE self, VALUE str, VALUE other) { + return rb_str_cat_cstr(str, StringValueCStr(other)); +} + +VALUE string_spec_rb_str_cat_cstr_constant(VALUE self, VALUE str) { + return rb_str_cat_cstr(str, "?"); +} + +VALUE string_spec_rb_str_cmp(VALUE self, VALUE str1, VALUE str2) { + return INT2NUM(rb_str_cmp(str1, str2)); +} + +VALUE string_spec_rb_str_strlen(VALUE self, VALUE str) { + return LONG2NUM(rb_str_strlen(str)); +} + +VALUE string_spec_rb_str_conv_enc(VALUE self, VALUE str, VALUE from, VALUE to) { + rb_encoding* from_enc; + rb_encoding* to_enc; + + from_enc = rb_to_encoding(from); + + if (NIL_P(to)) { + to_enc = 0; + } else { + to_enc = rb_to_encoding(to); + } + + return rb_str_conv_enc(str, from_enc, to_enc); +} + +VALUE string_spec_rb_str_conv_enc_opts(VALUE self, VALUE str, VALUE from, VALUE to, + VALUE ecflags, VALUE ecopts) { + rb_encoding* from_enc; + rb_encoding* to_enc; + + from_enc = rb_to_encoding(from); + + if (NIL_P(to)) { + to_enc = 0; + } else { + to_enc = rb_to_encoding(to); + } + + return rb_str_conv_enc_opts(str, from_enc, to_enc, FIX2INT(ecflags), ecopts); +} + +VALUE string_spec_rb_str_drop_bytes(VALUE self, VALUE str, VALUE len) { + return rb_str_drop_bytes(str, NUM2LONG(len)); +} + +VALUE string_spec_rb_str_export(VALUE self, VALUE str) { + return rb_str_export(str); +} + +VALUE string_spec_rb_str_export_locale(VALUE self, VALUE str) { + return rb_str_export_locale(str); +} + +VALUE string_spec_rb_str_dup(VALUE self, VALUE str) { + return rb_str_dup(str); +} + +VALUE string_spec_rb_str_freeze(VALUE self, VALUE str) { + return rb_str_freeze(str); +} + +VALUE string_spec_rb_str_inspect(VALUE self, VALUE str) { + return rb_str_inspect(str); +} + +VALUE string_spec_rb_str_intern(VALUE self, VALUE str) { + return rb_str_intern(str); +} + +VALUE string_spec_rb_str_length(VALUE self, VALUE str) { + return rb_str_length(str); +} + +VALUE string_spec_rb_str_new(VALUE self, VALUE str, VALUE len) { + return rb_str_new(RSTRING_PTR(str), FIX2INT(len)); +} + +VALUE string_spec_rb_str_new_native(VALUE self, VALUE str, VALUE len) { + return rb_str_new(NATIVE_RSTRING_PTR(str), FIX2INT(len)); +} + +VALUE string_spec_rb_str_new_offset(VALUE self, VALUE str, VALUE offset, VALUE len) { + return rb_str_new(RSTRING_PTR(str) + FIX2INT(offset), FIX2INT(len)); +} + +VALUE string_spec_rb_str_new2(VALUE self, VALUE str) { + if (NIL_P(str)) { + return rb_str_new2(""); + } else { + return rb_str_new2(RSTRING_PTR(str)); + } +} + +VALUE string_spec_rb_str_encode(VALUE self, VALUE str, VALUE enc, VALUE flags, VALUE opts) { + return rb_str_encode(str, enc, FIX2INT(flags), opts); +} + +VALUE string_spec_rb_str_export_to_enc(VALUE self, VALUE str, VALUE enc) { + return rb_str_export_to_enc(str, rb_to_encoding(enc)); +} + +VALUE string_spec_rb_str_new_cstr(VALUE self, VALUE str) { + if (NIL_P(str)) { + return rb_str_new_cstr(""); + } else { + return rb_str_new_cstr(RSTRING_PTR(str)); + } +} + +VALUE string_spec_rb_external_str_new(VALUE self, VALUE str) { + return rb_external_str_new(RSTRING_PTR(str), RSTRING_LEN(str)); +} + +VALUE string_spec_rb_external_str_new_cstr(VALUE self, VALUE str) { + return rb_external_str_new_cstr(RSTRING_PTR(str)); +} + +VALUE string_spec_rb_external_str_new_with_enc(VALUE self, VALUE str, VALUE len, VALUE encoding) { + return rb_external_str_new_with_enc(RSTRING_PTR(str), FIX2LONG(len), rb_to_encoding(encoding)); +} + +VALUE string_spec_rb_locale_str_new(VALUE self, VALUE str, VALUE len) { + return rb_locale_str_new(RSTRING_PTR(str), FIX2INT(len)); +} + +VALUE string_spec_rb_locale_str_new_cstr(VALUE self, VALUE str) { + return rb_locale_str_new_cstr(RSTRING_PTR(str)); +} + +VALUE string_spec_rb_str_new3(VALUE self, VALUE str) { + return rb_str_new3(str); +} + +VALUE string_spec_rb_str_new4(VALUE self, VALUE str) { + return rb_str_new4(str); +} + +VALUE string_spec_rb_str_new5(VALUE self, VALUE str, VALUE ptr, VALUE len) { + return rb_str_new5(str, RSTRING_PTR(ptr), FIX2INT(len)); +} + +VALUE string_spec_rb_str_plus(VALUE self, VALUE str1, VALUE str2) { + return rb_str_plus(str1, str2); +} + +VALUE string_spec_rb_str_times(VALUE self, VALUE str, VALUE times) { + return rb_str_times(str, times); +} + +VALUE string_spec_rb_str_modify_expand(VALUE self, VALUE str, VALUE size) { + rb_str_modify_expand(str, FIX2LONG(size)); + return str; +} + +VALUE string_spec_rb_str_resize(VALUE self, VALUE str, VALUE size) { + return rb_str_resize(str, FIX2INT(size)); +} + +VALUE string_spec_rb_str_resize_RSTRING_LEN(VALUE self, VALUE str, VALUE size) { + VALUE modified = rb_str_resize(str, FIX2INT(size)); + return INT2FIX(RSTRING_LEN(modified)); +} + +VALUE string_spec_rb_str_resize_copy(VALUE self, VALUE str) { + rb_str_modify_expand(str, 5); + char *buffer = RSTRING_PTR(str); + buffer[1] = 'e'; + buffer[2] = 's'; + buffer[3] = 't'; + rb_str_resize(str, 4); + return str; +} + +VALUE string_spec_rb_str_split(VALUE self, VALUE str) { + return rb_str_split(str, ","); +} + +VALUE string_spec_rb_str_subseq(VALUE self, VALUE str, VALUE beg, VALUE len) { + return rb_str_subseq(str, FIX2INT(beg), FIX2INT(len)); +} + +VALUE string_spec_rb_str_substr(VALUE self, VALUE str, VALUE beg, VALUE len) { + return rb_str_substr(str, FIX2INT(beg), FIX2INT(len)); +} + +VALUE string_spec_rb_str_to_str(VALUE self, VALUE arg) { + return rb_str_to_str(arg); +} + +VALUE string_spec_RSTRING_LEN(VALUE self, VALUE str) { + return INT2FIX(RSTRING_LEN(str)); +} + +VALUE string_spec_RSTRING_LENINT(VALUE self, VALUE str) { + return INT2FIX(RSTRING_LENINT(str)); +} + +VALUE string_spec_RSTRING_PTR_iterate(VALUE self, VALUE str) { + int i; + char* ptr; + + ptr = RSTRING_PTR(str); + for(i = 0; i < RSTRING_LEN(str); i++) { + rb_yield(CHR2FIX(ptr[i])); + } + return Qnil; +} + +VALUE string_spec_RSTRING_PTR_iterate_uint32(VALUE self, VALUE str) { + uint32_t* ptr; + long i, l = RSTRING_LEN(str) / sizeof(uint32_t); + + ptr = (uint32_t *)RSTRING_PTR(str); + for(i = 0; i < l; i++) { + rb_yield(UINT2NUM(ptr[i])); + } + return Qnil; +} + +VALUE string_spec_RSTRING_PTR_short_memcpy(VALUE self, VALUE str) { + /* Short memcpy operations may be optimised by the compiler to a single write. */ + if (RSTRING_LEN(str) >= 8) { + memcpy(RSTRING_PTR(str), "Infinity", 8); + } + return str; +} + +VALUE string_spec_RSTRING_PTR_assign(VALUE self, VALUE str, VALUE chr) { + int i; + char c; + char* ptr; + + ptr = RSTRING_PTR(str); + c = FIX2INT(chr); + + for(i = 0; i < RSTRING_LEN(str); i++) { + ptr[i] = c; + } + return Qnil; +} + +VALUE string_spec_RSTRING_PTR_set(VALUE self, VALUE str, VALUE i, VALUE chr) { + RSTRING_PTR(str)[FIX2INT(i)] = (char) FIX2INT(chr); + return str; +} + +VALUE string_spec_RSTRING_PTR_after_funcall(VALUE self, VALUE str, VALUE cb) { + /* Silence gcc 4.3.2 warning about computed value not used */ + if (RSTRING_PTR(str)) { /* force it out */ + rb_funcall(cb, rb_intern("call"), 1, str); + } + + return rb_str_new2(RSTRING_PTR(str)); +} + +VALUE string_spec_RSTRING_PTR_after_yield(VALUE self, VALUE str) { + char* ptr = NATIVE_RSTRING_PTR(str); + long len = RSTRING_LEN(str); + VALUE from_rstring_ptr; + + ptr[0] = '1'; + rb_yield(str); + ptr[2] = '2'; + + from_rstring_ptr = rb_str_new(ptr, len); + return from_rstring_ptr; +} + +VALUE string_spec_RSTRING_PTR_read(VALUE self, VALUE str, VALUE path) { + char *cpath = StringValueCStr(path); + int fd = open(cpath, O_RDONLY); + VALUE capacities = rb_ary_new(); + if (fd < 0) { + rb_syserr_fail(errno, "open"); + } + + rb_str_modify_expand(str, 30); + rb_ary_push(capacities, SIZET2NUM(rb_str_capacity(str))); + char *buffer = RSTRING_PTR(str); + if (read(fd, buffer, 30) < 0) { + rb_syserr_fail(errno, "read"); + } + + rb_str_modify_expand(str, 53); + rb_ary_push(capacities, SIZET2NUM(rb_str_capacity(str))); + char *buffer2 = RSTRING_PTR(str); + if (read(fd, buffer2 + 30, 53 - 30) < 0) { + rb_syserr_fail(errno, "read"); + } + + rb_str_set_len(str, 53); + close(fd); + return capacities; +} + +VALUE string_spec_RSTRING_PTR_null_terminate(VALUE self, VALUE str, VALUE min_length) { + char* ptr = RSTRING_PTR(str); + char* end = ptr + RSTRING_LEN(str); + return rb_str_new(end, FIX2LONG(min_length)); +} + +VALUE string_spec_StringValue(VALUE self, VALUE str) { + return StringValue(str); +} + +static VALUE string_spec_SafeStringValue(VALUE self, VALUE str) { + SafeStringValue(str); + return str; +} + +static VALUE string_spec_rb_str_hash(VALUE self, VALUE str) { + st_index_t val = rb_str_hash(str); + + return ST2FIX(val); +} + +static VALUE string_spec_rb_str_update(VALUE self, VALUE str, VALUE beg, VALUE end, VALUE replacement) { + rb_str_update(str, FIX2LONG(beg), FIX2LONG(end), replacement); + return str; +} + +static VALUE string_spec_rb_str_free(VALUE self, VALUE str) { + rb_str_free(str); + return Qnil; +} + +static VALUE string_spec_rb_sprintf1(VALUE self, VALUE str, VALUE repl) { + return rb_sprintf(RSTRING_PTR(str), RSTRING_PTR(repl)); +} + +static VALUE string_spec_rb_sprintf2(VALUE self, VALUE str, VALUE repl1, VALUE repl2) { + return rb_sprintf(RSTRING_PTR(str), RSTRING_PTR(repl1), RSTRING_PTR(repl2)); +} + +static VALUE string_spec_rb_sprintf3(VALUE self, VALUE str) { + return rb_sprintf("Result: %" PRIsVALUE ".", str); +} + +static VALUE string_spec_rb_sprintf4(VALUE self, VALUE str) { + return rb_sprintf("Result: %+" PRIsVALUE ".", str); +} + +static VALUE string_spec_rb_sprintf5(VALUE self, VALUE width, VALUE precision, VALUE str) { + return rb_sprintf("Result: %*.*s.", FIX2INT(width), FIX2INT(precision), RSTRING_PTR(str)); +} + +static VALUE string_spec_rb_sprintf6(VALUE self, VALUE width, VALUE precision, VALUE str) { + return rb_sprintf("Result: %*.*" PRIsVALUE ".", FIX2INT(width), FIX2INT(precision), str); +} + +static VALUE string_spec_rb_sprintf7(VALUE self, VALUE str, VALUE obj) { + VALUE results = rb_ary_new(); + rb_ary_push(results, rb_sprintf(RSTRING_PTR(str), obj)); + char cstr[256]; + int len = snprintf(cstr, 256, RSTRING_PTR(str), obj); + rb_ary_push(results, rb_str_new(cstr, len)); + return results; +} + +static VALUE string_spec_rb_sprintf8(VALUE self, VALUE str, VALUE num) { + VALUE results = rb_ary_new(); + rb_ary_push(results, rb_sprintf(RSTRING_PTR(str), FIX2LONG(num))); + char cstr[256]; + int len = snprintf(cstr, 256, RSTRING_PTR(str), FIX2LONG(num)); + rb_ary_push(results, rb_str_new(cstr, len)); + return results; +} + +PRINTF_ARGS(static VALUE string_spec_rb_vsprintf_worker(char* fmt, ...), 1, 2); +static VALUE string_spec_rb_vsprintf_worker(char* fmt, ...) { + va_list varargs; + VALUE str; + + va_start(varargs, fmt); + str = rb_vsprintf(fmt, varargs); + va_end(varargs); + + return str; +} + +static VALUE string_spec_rb_vsprintf(VALUE self, VALUE fmt, VALUE str, VALUE i, VALUE f) { + return string_spec_rb_vsprintf_worker(RSTRING_PTR(fmt), RSTRING_PTR(str), + FIX2INT(i), RFLOAT_VALUE(f)); +} + +VALUE string_spec_rb_str_equal(VALUE self, VALUE str1, VALUE str2) { + return rb_str_equal(str1, str2); +} + +static VALUE string_spec_rb_usascii_str_new(VALUE self, VALUE str, VALUE len) { + return rb_usascii_str_new(RSTRING_PTR(str), NUM2INT(len)); +} + +static VALUE string_spec_rb_usascii_str_new_lit(VALUE self) { + return rb_usascii_str_new_lit("nokogiri"); +} + +static VALUE string_spec_rb_usascii_str_new_lit_non_ascii(VALUE self) { + return rb_usascii_str_new_lit("r\xc3\xa9sum\xc3\xa9"); +} + +static VALUE string_spec_rb_usascii_str_new_cstr(VALUE self, VALUE str) { + return rb_usascii_str_new_cstr(RSTRING_PTR(str)); +} + +static VALUE string_spec_rb_String(VALUE self, VALUE val) { + return rb_String(val); +} + +static VALUE string_spec_rb_string_value_cstr(VALUE self, VALUE str) { + char *c_str = rb_string_value_cstr(&str); + return c_str ? Qtrue : Qfalse; +} + +static VALUE string_spec_rb_str_modify(VALUE self, VALUE str) { + rb_str_modify(str); + return str; +} + +static VALUE string_spec_rb_utf8_str_new_static(VALUE self) { + return rb_utf8_str_new_static("nokogiri", 8); +} + +static VALUE string_spec_rb_utf8_str_new(VALUE self) { + return rb_utf8_str_new("nokogiri", 8); +} + +static VALUE string_spec_rb_utf8_str_new_cstr(VALUE self) { + return rb_utf8_str_new_cstr("nokogiri"); +} + +PRINTF_ARGS(static VALUE call_rb_str_vcatf(VALUE mesg, const char *fmt, ...), 2, 3); +static VALUE call_rb_str_vcatf(VALUE mesg, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + VALUE result = rb_str_vcatf(mesg, fmt, ap); + va_end(ap); + return result; +} + +static VALUE string_spec_rb_str_vcatf(VALUE self, VALUE mesg) { + return call_rb_str_vcatf(mesg, "fmt %d %d number", 42, 7); +} + +static VALUE string_spec_rb_str_catf(VALUE self, VALUE mesg) { + return rb_str_catf(mesg, "fmt %d %d number", 41, 6); +} + +static VALUE string_spec_rb_str_locktmp(VALUE self, VALUE str) { + return rb_str_locktmp(str); +} + +static VALUE string_spec_rb_str_unlocktmp(VALUE self, VALUE str) { + return rb_str_unlocktmp(str); +} + +static VALUE string_spec_rb_enc_interned_str_cstr(VALUE self, VALUE str, VALUE enc) { + rb_encoding *e = NIL_P(enc) ? 0 : rb_to_encoding(enc); + return rb_enc_interned_str_cstr(RSTRING_PTR(str), e); +} + +static VALUE string_spec_rb_enc_interned_str(VALUE self, VALUE str, VALUE len, VALUE enc) { + rb_encoding *e = NIL_P(enc) ? 0 : rb_to_encoding(enc); + return rb_enc_interned_str(RSTRING_PTR(str), FIX2LONG(len), e); +} + +static VALUE string_spec_rb_str_to_interned_str(VALUE self, VALUE str) { + return rb_str_to_interned_str(str); +} + +void Init_string_spec(void) { + VALUE cls = rb_define_class("CApiStringSpecs", rb_cObject); + rb_define_method(cls, "rb_cstr2inum", string_spec_rb_cstr2inum, 2); + rb_define_method(cls, "rb_cstr_to_inum", string_spec_rb_cstr_to_inum, 3); + rb_define_method(cls, "rb_str2inum", string_spec_rb_str2inum, 2); + rb_define_method(cls, "rb_str_append", string_spec_rb_str_append, 2); + rb_define_method(cls, "rb_str_buf_new", string_spec_rb_str_buf_new, 2); + rb_define_method(cls, "rb_str_capacity", string_spec_rb_str_capacity, 1); + rb_define_method(cls, "rb_str_buf_new2", string_spec_rb_str_buf_new2, 0); + rb_define_method(cls, "rb_str_tmp_new", string_spec_rb_str_tmp_new, 1); + rb_define_method(cls, "rb_str_tmp_new_klass", string_spec_rb_str_tmp_new_klass, 1); + rb_define_method(cls, "rb_str_buf_append", string_spec_rb_str_buf_append, 2); + rb_define_method(cls, "rb_str_buf_cat", string_spec_rb_str_buf_cat, 1); + rb_define_method(cls, "rb_enc_str_buf_cat", string_spec_rb_enc_str_buf_cat, 3); + rb_define_method(cls, "rb_str_cat", string_spec_rb_str_cat, 1); + rb_define_method(cls, "rb_str_cat2", string_spec_rb_str_cat2, 1); + rb_define_method(cls, "rb_str_cat_cstr", string_spec_rb_str_cat_cstr, 2); + rb_define_method(cls, "rb_str_cat_cstr_constant", string_spec_rb_str_cat_cstr_constant, 1); + rb_define_method(cls, "rb_str_cmp", string_spec_rb_str_cmp, 2); + rb_define_method(cls, "rb_str_strlen", string_spec_rb_str_strlen, 1); + rb_define_method(cls, "rb_str_conv_enc", string_spec_rb_str_conv_enc, 3); + rb_define_method(cls, "rb_str_conv_enc_opts", string_spec_rb_str_conv_enc_opts, 5); + rb_define_method(cls, "rb_str_drop_bytes", string_spec_rb_str_drop_bytes, 2); + rb_define_method(cls, "rb_str_export", string_spec_rb_str_export, 1); + rb_define_method(cls, "rb_str_export_locale", string_spec_rb_str_export_locale, 1); + rb_define_method(cls, "rb_str_dup", string_spec_rb_str_dup, 1); + rb_define_method(cls, "rb_str_freeze", string_spec_rb_str_freeze, 1); + rb_define_method(cls, "rb_str_inspect", string_spec_rb_str_inspect, 1); + rb_define_method(cls, "rb_str_intern", string_spec_rb_str_intern, 1); + rb_define_method(cls, "rb_str_length", string_spec_rb_str_length, 1); + rb_define_method(cls, "rb_str_new", string_spec_rb_str_new, 2); + rb_define_method(cls, "rb_str_new_native", string_spec_rb_str_new_native, 2); + rb_define_method(cls, "rb_str_new_offset", string_spec_rb_str_new_offset, 3); + rb_define_method(cls, "rb_str_new2", string_spec_rb_str_new2, 1); + rb_define_method(cls, "rb_str_encode", string_spec_rb_str_encode, 4); + rb_define_method(cls, "rb_str_export_to_enc", string_spec_rb_str_export_to_enc, 2); + rb_define_method(cls, "rb_str_new_cstr", string_spec_rb_str_new_cstr, 1); + rb_define_method(cls, "rb_external_str_new", string_spec_rb_external_str_new, 1); + rb_define_method(cls, "rb_external_str_new_cstr", string_spec_rb_external_str_new_cstr, 1); + rb_define_method(cls, "rb_external_str_new_with_enc", string_spec_rb_external_str_new_with_enc, 3); + rb_define_method(cls, "rb_locale_str_new", string_spec_rb_locale_str_new, 2); + rb_define_method(cls, "rb_locale_str_new_cstr", string_spec_rb_locale_str_new_cstr, 1); + rb_define_method(cls, "rb_str_new3", string_spec_rb_str_new3, 1); + rb_define_method(cls, "rb_str_new4", string_spec_rb_str_new4, 1); + rb_define_method(cls, "rb_str_new5", string_spec_rb_str_new5, 3); + rb_define_method(cls, "rb_str_plus", string_spec_rb_str_plus, 2); + rb_define_method(cls, "rb_str_times", string_spec_rb_str_times, 2); + rb_define_method(cls, "rb_str_modify_expand", string_spec_rb_str_modify_expand, 2); + rb_define_method(cls, "rb_str_resize", string_spec_rb_str_resize, 2); + rb_define_method(cls, "rb_str_resize_RSTRING_LEN", string_spec_rb_str_resize_RSTRING_LEN, 2); + rb_define_method(cls, "rb_str_resize_copy", string_spec_rb_str_resize_copy, 1); + rb_define_method(cls, "rb_str_set_len", string_spec_rb_str_set_len, 2); + rb_define_method(cls, "rb_str_set_len_RSTRING_LEN", string_spec_rb_str_set_len_RSTRING_LEN, 2); + rb_define_method(cls, "rb_str_split", string_spec_rb_str_split, 1); + rb_define_method(cls, "rb_str_subseq", string_spec_rb_str_subseq, 3); + rb_define_method(cls, "rb_str_substr", string_spec_rb_str_substr, 3); + rb_define_method(cls, "rb_str_to_str", string_spec_rb_str_to_str, 1); + rb_define_method(cls, "RSTRING_LEN", string_spec_RSTRING_LEN, 1); + rb_define_method(cls, "RSTRING_LENINT", string_spec_RSTRING_LENINT, 1); + rb_define_method(cls, "RSTRING_PTR_iterate", string_spec_RSTRING_PTR_iterate, 1); + rb_define_method(cls, "RSTRING_PTR_iterate_uint32", string_spec_RSTRING_PTR_iterate_uint32, 1); + rb_define_method(cls, "RSTRING_PTR_short_memcpy", string_spec_RSTRING_PTR_short_memcpy, 1); + rb_define_method(cls, "RSTRING_PTR_assign", string_spec_RSTRING_PTR_assign, 2); + rb_define_method(cls, "RSTRING_PTR_set", string_spec_RSTRING_PTR_set, 3); + rb_define_method(cls, "RSTRING_PTR_after_funcall", string_spec_RSTRING_PTR_after_funcall, 2); + rb_define_method(cls, "RSTRING_PTR_after_yield", string_spec_RSTRING_PTR_after_yield, 1); + rb_define_method(cls, "RSTRING_PTR_read", string_spec_RSTRING_PTR_read, 2); + rb_define_method(cls, "RSTRING_PTR_null_terminate", string_spec_RSTRING_PTR_null_terminate, 2); + rb_define_method(cls, "StringValue", string_spec_StringValue, 1); + rb_define_method(cls, "SafeStringValue", string_spec_SafeStringValue, 1); + rb_define_method(cls, "rb_str_hash", string_spec_rb_str_hash, 1); + rb_define_method(cls, "rb_str_update", string_spec_rb_str_update, 4); + rb_define_method(cls, "rb_str_free", string_spec_rb_str_free, 1); + rb_define_method(cls, "rb_sprintf1", string_spec_rb_sprintf1, 2); + rb_define_method(cls, "rb_sprintf2", string_spec_rb_sprintf2, 3); + rb_define_method(cls, "rb_sprintf3", string_spec_rb_sprintf3, 1); + rb_define_method(cls, "rb_sprintf4", string_spec_rb_sprintf4, 1); + rb_define_method(cls, "rb_sprintf5", string_spec_rb_sprintf5, 3); + rb_define_method(cls, "rb_sprintf6", string_spec_rb_sprintf6, 3); + rb_define_method(cls, "rb_sprintf7", string_spec_rb_sprintf7, 2); + rb_define_method(cls, "rb_sprintf8", string_spec_rb_sprintf8, 2); + rb_define_method(cls, "rb_vsprintf", string_spec_rb_vsprintf, 4); + rb_define_method(cls, "rb_str_equal", string_spec_rb_str_equal, 2); + rb_define_method(cls, "rb_usascii_str_new", string_spec_rb_usascii_str_new, 2); + rb_define_method(cls, "rb_usascii_str_new_lit", string_spec_rb_usascii_str_new_lit, 0); + rb_define_method(cls, "rb_usascii_str_new_lit_non_ascii", string_spec_rb_usascii_str_new_lit_non_ascii, 0); + rb_define_method(cls, "rb_usascii_str_new_cstr", string_spec_rb_usascii_str_new_cstr, 1); + rb_define_method(cls, "rb_String", string_spec_rb_String, 1); + rb_define_method(cls, "rb_string_value_cstr", string_spec_rb_string_value_cstr, 1); + rb_define_method(cls, "rb_str_modify", string_spec_rb_str_modify, 1); + rb_define_method(cls, "rb_utf8_str_new_static", string_spec_rb_utf8_str_new_static, 0); + rb_define_method(cls, "rb_utf8_str_new", string_spec_rb_utf8_str_new, 0); + rb_define_method(cls, "rb_utf8_str_new_cstr", string_spec_rb_utf8_str_new_cstr, 0); + rb_define_method(cls, "rb_str_vcatf", string_spec_rb_str_vcatf, 1); + rb_define_method(cls, "rb_str_catf", string_spec_rb_str_catf, 1); + rb_define_method(cls, "rb_str_locktmp", string_spec_rb_str_locktmp, 1); + rb_define_method(cls, "rb_str_unlocktmp", string_spec_rb_str_unlocktmp, 1); + rb_define_method(cls, "rb_enc_interned_str_cstr", string_spec_rb_enc_interned_str_cstr, 2); + rb_define_method(cls, "rb_enc_interned_str", string_spec_rb_enc_interned_str, 3); + rb_define_method(cls, "rb_str_to_interned_str", string_spec_rb_str_to_interned_str, 1); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/struct_spec.c b/spec/ruby/optional/capi/ext/struct_spec.c new file mode 100644 index 0000000000..756cfca8dd --- /dev/null +++ b/spec/ruby/optional/capi/ext/struct_spec.c @@ -0,0 +1,105 @@ +#include "ruby.h" +#include "rubyspec.h" + +#include "ruby/intern.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static VALUE struct_spec_rb_struct_aref(VALUE self, VALUE st, VALUE key) { + return rb_struct_aref(st, key); +} + +static VALUE struct_spec_rb_struct_getmember(VALUE self, VALUE st, VALUE key) { + return rb_struct_getmember(st, SYM2ID(key)); +} + +static VALUE struct_spec_rb_struct_s_members(VALUE self, VALUE klass) { + return rb_ary_dup(rb_struct_s_members(klass)); +} + +static VALUE struct_spec_rb_struct_members(VALUE self, VALUE st) { + return rb_ary_dup(rb_struct_members(st)); +} + +static VALUE struct_spec_rb_struct_aset(VALUE self, VALUE st, VALUE key, VALUE value) { + return rb_struct_aset(st, key, value); +} + +/* Only allow setting three attributes, should be sufficient for testing. */ +static VALUE struct_spec_rb_struct_define(VALUE self, VALUE name, + VALUE attr1, VALUE attr2, VALUE attr3) { + + const char *a1 = StringValuePtr(attr1); + const char *a2 = StringValuePtr(attr2); + const char *a3 = StringValuePtr(attr3); + char *nm = NULL; + + if (name != Qnil) nm = StringValuePtr(name); + + return rb_struct_define(nm, a1, a2, a3, NULL); +} + +/* Only allow setting three attributes, should be sufficient for testing. */ +static VALUE struct_spec_rb_struct_define_under(VALUE self, VALUE outer, + VALUE name, VALUE attr1, VALUE attr2, VALUE attr3) { + + const char *nm = StringValuePtr(name); + const char *a1 = StringValuePtr(attr1); + const char *a2 = StringValuePtr(attr2); + const char *a3 = StringValuePtr(attr3); + + return rb_struct_define_under(outer, nm, a1, a2, a3, NULL); +} + +static VALUE struct_spec_rb_struct_new(VALUE self, VALUE klass, + VALUE a, VALUE b, VALUE c) { + return rb_struct_new(klass, a, b, c); +} + +static VALUE struct_spec_rb_struct_size(VALUE self, VALUE st) { + return rb_struct_size(st); +} + +static VALUE struct_spec_rb_struct_initialize(VALUE self, VALUE st, VALUE values) { + return rb_struct_initialize(st, values); +} + +#if defined(RUBY_VERSION_IS_3_3) +/* Only allow setting three attributes, should be sufficient for testing. */ +static VALUE struct_spec_rb_data_define(VALUE self, VALUE superclass, + VALUE attr1, VALUE attr2, VALUE attr3) { + + const char *a1 = StringValuePtr(attr1); + const char *a2 = StringValuePtr(attr2); + const char *a3 = StringValuePtr(attr3); + + if (superclass == Qnil) { + superclass = 0; + } + + return rb_data_define(superclass, a1, a2, a3, NULL); +} +#endif + +void Init_struct_spec(void) { + VALUE cls = rb_define_class("CApiStructSpecs", rb_cObject); + rb_define_method(cls, "rb_struct_aref", struct_spec_rb_struct_aref, 2); + rb_define_method(cls, "rb_struct_getmember", struct_spec_rb_struct_getmember, 2); + rb_define_method(cls, "rb_struct_s_members", struct_spec_rb_struct_s_members, 1); + rb_define_method(cls, "rb_struct_members", struct_spec_rb_struct_members, 1); + rb_define_method(cls, "rb_struct_aset", struct_spec_rb_struct_aset, 3); + rb_define_method(cls, "rb_struct_define", struct_spec_rb_struct_define, 4); + rb_define_method(cls, "rb_struct_define_under", struct_spec_rb_struct_define_under, 5); + rb_define_method(cls, "rb_struct_new", struct_spec_rb_struct_new, 4); + rb_define_method(cls, "rb_struct_size", struct_spec_rb_struct_size, 1); + rb_define_method(cls, "rb_struct_initialize", struct_spec_rb_struct_initialize, 2); +#if defined(RUBY_VERSION_IS_3_3) + rb_define_method(cls, "rb_data_define", struct_spec_rb_data_define, 4); +#endif +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/symbol_spec.c b/spec/ruby/optional/capi/ext/symbol_spec.c new file mode 100644 index 0000000000..ba88635faa --- /dev/null +++ b/spec/ruby/optional/capi/ext/symbol_spec.c @@ -0,0 +1,116 @@ +#include "ruby.h" +#include "rubyspec.h" + +#include "ruby/encoding.h" + +#ifdef __cplusplus +extern "C" { +#endif + +VALUE symbol_spec_SYMBOL_P(VALUE self, VALUE obj) { + return SYMBOL_P(obj) ? Qtrue : Qfalse; +} + +VALUE symbol_spec_rb_intern(VALUE self, VALUE string) { + return ID2SYM(rb_intern(RSTRING_PTR(string))); +} + +VALUE symbol_spec_rb_intern2(VALUE self, VALUE string, VALUE len) { + return ID2SYM(rb_intern2(RSTRING_PTR(string), FIX2LONG(len))); +} + +VALUE symbol_spec_rb_intern_const(VALUE self, VALUE string) { + return ID2SYM(rb_intern_const(RSTRING_PTR(string))); +} + +VALUE symbol_spec_rb_intern_c_compare(VALUE self, VALUE string, VALUE sym) { + ID symbol = rb_intern(RSTRING_PTR(string)); + return (SYM2ID(sym) == symbol) ? Qtrue : Qfalse; +} + +VALUE symbol_spec_rb_intern2_c_compare(VALUE self, VALUE string, VALUE len, VALUE sym) { + ID symbol = rb_intern2(RSTRING_PTR(string), FIX2LONG(len)); + return (SYM2ID(sym) == symbol) ? Qtrue : Qfalse; +} + +VALUE symbol_spec_rb_intern3(VALUE self, VALUE string, VALUE len, VALUE enc) { + return ID2SYM(rb_intern3(RSTRING_PTR(string), FIX2LONG(len), rb_enc_get(enc))); +} + +VALUE symbol_spec_rb_intern3_c_compare(VALUE self, VALUE string, VALUE len, VALUE enc, VALUE sym) { + ID symbol = rb_intern3(RSTRING_PTR(string), FIX2LONG(len), rb_enc_get(enc)); + return (SYM2ID(sym) == symbol) ? Qtrue : Qfalse; +} + +VALUE symbol_spec_rb_id2name(VALUE self, VALUE symbol) { + const char* c_str = rb_id2name(SYM2ID(symbol)); + return rb_str_new(c_str, strlen(c_str)); +} + +VALUE symbol_spec_rb_id2name_id_zero(VALUE self) { + const char* c_str = rb_id2name((ID) 0); + return c_str ? rb_str_new(c_str, strlen(c_str)) : Qnil; +} + +VALUE symbol_spec_rb_id2str(VALUE self, VALUE symbol) { + return rb_id2str(SYM2ID(symbol)); +} + +VALUE symbol_spec_rb_id2str_id_zero(VALUE self) { + return rb_id2str((ID) 0); +} + +VALUE symbol_spec_rb_intern_str(VALUE self, VALUE str) { + return ID2SYM(rb_intern_str(str)); +} + +VALUE symbol_spec_rb_check_symbol_cstr(VALUE self, VALUE str) { + return rb_check_symbol_cstr(RSTRING_PTR(str), RSTRING_LEN(str), rb_enc_get(str)); +} + +VALUE symbol_spec_rb_is_class_id(VALUE self, VALUE sym) { + return rb_is_class_id(SYM2ID(sym)) ? Qtrue : Qfalse; +} + +VALUE symbol_spec_rb_is_const_id(VALUE self, VALUE sym) { + return rb_is_const_id(SYM2ID(sym)) ? Qtrue : Qfalse; +} + +VALUE symbol_spec_rb_is_instance_id(VALUE self, VALUE sym) { + return rb_is_instance_id(SYM2ID(sym)) ? Qtrue : Qfalse; +} + +VALUE symbol_spec_rb_sym2str(VALUE self, VALUE sym) { + return rb_sym2str(sym); +} + +VALUE symbol_spec_rb_to_symbol(VALUE self, VALUE val) { + return rb_to_symbol(val); +} + +void Init_symbol_spec(void) { + VALUE cls = rb_define_class("CApiSymbolSpecs", rb_cObject); + rb_define_method(cls, "SYMBOL_P", symbol_spec_SYMBOL_P, 1); + rb_define_method(cls, "rb_intern", symbol_spec_rb_intern, 1); + rb_define_method(cls, "rb_intern2", symbol_spec_rb_intern2, 2); + rb_define_method(cls, "rb_intern_const", symbol_spec_rb_intern_const, 1); + rb_define_method(cls, "rb_intern_c_compare", symbol_spec_rb_intern_c_compare, 2); + rb_define_method(cls, "rb_intern2_c_compare", symbol_spec_rb_intern2_c_compare, 3); + rb_define_method(cls, "rb_intern3", symbol_spec_rb_intern3, 3); + rb_define_method(cls, "rb_intern3_c_compare", symbol_spec_rb_intern3_c_compare, 4); + rb_define_method(cls, "rb_id2name", symbol_spec_rb_id2name, 1); + rb_define_method(cls, "rb_id2name_id_zero", symbol_spec_rb_id2name_id_zero, 0); + rb_define_method(cls, "rb_id2str", symbol_spec_rb_id2str, 1); + rb_define_method(cls, "rb_id2str_id_zero", symbol_spec_rb_id2str_id_zero, 0); + rb_define_method(cls, "rb_intern_str", symbol_spec_rb_intern_str, 1); + rb_define_method(cls, "rb_check_symbol_cstr", symbol_spec_rb_check_symbol_cstr, 1); + rb_define_method(cls, "rb_is_class_id", symbol_spec_rb_is_class_id, 1); + rb_define_method(cls, "rb_is_const_id", symbol_spec_rb_is_const_id, 1); + rb_define_method(cls, "rb_is_instance_id", symbol_spec_rb_is_instance_id, 1); + rb_define_method(cls, "rb_sym2str", symbol_spec_rb_sym2str, 1); + rb_define_method(cls, "rb_to_symbol", symbol_spec_rb_to_symbol, 1); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/thread_spec.c b/spec/ruby/optional/capi/ext/thread_spec.c new file mode 100644 index 0000000000..ac77e4e813 --- /dev/null +++ b/spec/ruby/optional/capi/ext/thread_spec.c @@ -0,0 +1,195 @@ +#include "ruby.h" +#include "ruby/thread.h" +#include "rubyspec.h" + +#include <math.h> +#include <errno.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#if defined(_WIN32) +#include "ruby/win32.h" +#define read rb_w32_read +#define write rb_w32_write +#define pipe rb_w32_pipe +#endif + +#ifndef _WIN32 +#include <pthread.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +static VALUE thread_spec_rb_thread_alone(VALUE self) { + return rb_thread_alone() ? Qtrue : Qfalse; +} + +/* This is unblocked by unblock_func(). */ +static void* blocking_gvl_func(void* data) { + int rfd = *(int *)data; + char dummy = ' '; + ssize_t r; + + do { + r = read(rfd, &dummy, 1); + } while (r == -1 && errno == EINTR); + + close(rfd); + + return (void*)((r == 1 && dummy == 'A') ? Qtrue : Qfalse); +} + +static void unblock_gvl_func(void *data) { + int wfd = *(int *)data; + char dummy = 'A'; + ssize_t r; + + do { + r = write(wfd, &dummy, 1); + } while (r == -1 && errno == EINTR); + + close(wfd); +} + +/* Returns true if the thread is interrupted. */ +static VALUE thread_spec_rb_thread_call_without_gvl(VALUE self) { + int fds[2]; + void* ret; + + if (pipe(fds) == -1) { + rb_raise(rb_eRuntimeError, "could not create pipe"); + } + ret = rb_thread_call_without_gvl(blocking_gvl_func, &fds[0], + unblock_gvl_func, &fds[1]); + return (VALUE)ret; +} + +/* This is unblocked by a signal. */ +static void* blocking_gvl_func_for_ubf_io(void *data) { + int rfd = (int)(size_t)data; + char dummy; + + if (read(rfd, &dummy, 1) == -1 && errno == EINTR) { + return (void*)Qtrue; + } else { + return (void*)Qfalse; + } +} + +/* Returns true if the thread is interrupted. */ +static VALUE thread_spec_rb_thread_call_without_gvl_with_ubf_io(VALUE self) { + int fds[2]; + void* ret; + + if (pipe(fds) == -1) { + rb_raise(rb_eRuntimeError, "could not create pipe"); + } + + ret = rb_thread_call_without_gvl(blocking_gvl_func_for_ubf_io, + (void*)(size_t)fds[0], RUBY_UBF_IO, 0); + close(fds[0]); + close(fds[1]); + return (VALUE)ret; +} + +static VALUE thread_spec_rb_thread_current(VALUE self) { + return rb_thread_current(); +} + +static VALUE thread_spec_rb_thread_local_aref(VALUE self, VALUE thr, VALUE sym) { + return rb_thread_local_aref(thr, SYM2ID(sym)); +} + +static VALUE thread_spec_rb_thread_local_aset(VALUE self, VALUE thr, VALUE sym, VALUE value) { + return rb_thread_local_aset(thr, SYM2ID(sym), value); +} + +static VALUE thread_spec_rb_thread_wakeup(VALUE self, VALUE thr) { + return rb_thread_wakeup(thr); +} + +static VALUE thread_spec_rb_thread_wait_for(VALUE self, VALUE s, VALUE ms) { + struct timeval tv; + tv.tv_sec = NUM2INT(s); + tv.tv_usec = NUM2INT(ms); + rb_thread_wait_for(tv); + return Qnil; +} + +VALUE thread_spec_call_proc(void *arg_ptr) { + VALUE arg_array = (VALUE)arg_ptr; + VALUE arg = rb_ary_pop(arg_array); + VALUE proc = rb_ary_pop(arg_array); + return rb_funcall(proc, rb_intern("call"), 1, arg); +} + +static VALUE thread_spec_rb_thread_create(VALUE self, VALUE proc, VALUE arg) { + VALUE args = rb_ary_new(); + rb_ary_push(args, proc); + rb_ary_push(args, arg); + + return rb_thread_create(thread_spec_call_proc, (void*)args); +} + +static VALUE thread_spec_ruby_native_thread_p(VALUE self) { + if (ruby_native_thread_p()) { + return Qtrue; + } else { + return Qfalse; + } +} + +#ifndef _WIN32 +static VALUE false_result = Qfalse; +static VALUE true_result = Qtrue; + +static void *new_thread_check(void *args) { + if (ruby_native_thread_p()) { + return &true_result; + } else { + return &false_result; + } +} +#endif + +static VALUE thread_spec_ruby_native_thread_p_new_thread(VALUE self) { +#ifndef _WIN32 + pthread_t t; + void *result = &true_result; + pthread_create(&t, NULL, new_thread_check, NULL); + pthread_join(t, &result); + return *(VALUE *)result; +#else + return Qfalse; +#endif +} + +#ifdef RUBY_VERSION_IS_4_0 +static VALUE thread_spec_ruby_thread_has_gvl_p(VALUE self) { + return ruby_thread_has_gvl_p() ? Qtrue : Qfalse; +} +#endif + +void Init_thread_spec(void) { + VALUE cls = rb_define_class("CApiThreadSpecs", rb_cObject); + rb_define_method(cls, "rb_thread_alone", thread_spec_rb_thread_alone, 0); + rb_define_method(cls, "rb_thread_call_without_gvl", thread_spec_rb_thread_call_without_gvl, 0); + rb_define_method(cls, "rb_thread_call_without_gvl_with_ubf_io", thread_spec_rb_thread_call_without_gvl_with_ubf_io, 0); + rb_define_method(cls, "rb_thread_current", thread_spec_rb_thread_current, 0); + rb_define_method(cls, "rb_thread_local_aref", thread_spec_rb_thread_local_aref, 2); + rb_define_method(cls, "rb_thread_local_aset", thread_spec_rb_thread_local_aset, 3); + rb_define_method(cls, "rb_thread_wakeup", thread_spec_rb_thread_wakeup, 1); + rb_define_method(cls, "rb_thread_wait_for", thread_spec_rb_thread_wait_for, 2); + rb_define_method(cls, "rb_thread_create", thread_spec_rb_thread_create, 2); + rb_define_method(cls, "ruby_native_thread_p", thread_spec_ruby_native_thread_p, 0); + rb_define_method(cls, "ruby_native_thread_p_new_thread", thread_spec_ruby_native_thread_p_new_thread, 0); +#ifdef RUBY_VERSION_IS_4_0 + rb_define_method(cls, "ruby_thread_has_gvl_p", thread_spec_ruby_thread_has_gvl_p, 0); +#endif +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/time_spec.c b/spec/ruby/optional/capi/ext/time_spec.c new file mode 100644 index 0000000000..fec70dea9d --- /dev/null +++ b/spec/ruby/optional/capi/ext/time_spec.c @@ -0,0 +1,81 @@ +#include "ruby.h" +#include "rubyspec.h" + +#include <time.h> + +#ifdef __cplusplus +extern "C" { +#endif + +static VALUE time_spec_rb_time_new(VALUE self, VALUE sec, VALUE usec) { + return rb_time_new(NUM2TIMET(sec), NUM2LONG(usec)); +} + +static VALUE time_spec_rb_time_nano_new(VALUE self, VALUE sec, VALUE nsec) { + return rb_time_nano_new(NUM2TIMET(sec), NUM2LONG(nsec)); +} + +static VALUE time_spec_rb_time_num_new(VALUE self, VALUE ts, VALUE offset) { + return rb_time_num_new(ts, offset); +} + +static VALUE time_spec_rb_time_interval(VALUE self, VALUE ts) { + struct timeval interval = rb_time_interval(ts); + VALUE ary = rb_ary_new(); + rb_ary_push(ary, TIMET2NUM(interval.tv_sec)); + rb_ary_push(ary, TIMET2NUM(interval.tv_usec)); + return ary; +} + +static VALUE time_spec_rb_time_timeval(VALUE self, VALUE ts) { + struct timeval tv = rb_time_timeval(ts); + VALUE ary = rb_ary_new(); + rb_ary_push(ary, TIMET2NUM(tv.tv_sec)); + rb_ary_push(ary, TIMET2NUM(tv.tv_usec)); + return ary; +} + +static VALUE time_spec_rb_time_timespec(VALUE self, VALUE time) { + struct timespec ts = rb_time_timespec(time); + VALUE ary = rb_ary_new(); + rb_ary_push(ary, TIMET2NUM(ts.tv_sec)); + rb_ary_push(ary, TIMET2NUM(ts.tv_nsec)); + return ary; +} + +static VALUE time_spec_rb_time_timespec_new(VALUE self, VALUE sec, VALUE nsec, VALUE offset) { + struct timespec ts; + ts.tv_sec = NUM2TIMET(sec); + ts.tv_nsec = NUM2LONG(nsec); + + return rb_time_timespec_new(&ts, NUM2INT(offset)); +} + +static VALUE time_spec_rb_time_from_timspec_now(VALUE self, VALUE offset) { + struct timespec ts; + rb_timespec_now(&ts); + + return rb_time_timespec_new(&ts, NUM2INT(offset)); +} + +static VALUE time_spec_TIMET2NUM(VALUE self) { + time_t t = 10; + return TIMET2NUM(t); +} + +void Init_time_spec(void) { + VALUE cls = rb_define_class("CApiTimeSpecs", rb_cObject); + rb_define_method(cls, "rb_time_new", time_spec_rb_time_new, 2); + rb_define_method(cls, "TIMET2NUM", time_spec_TIMET2NUM, 0); + rb_define_method(cls, "rb_time_nano_new", time_spec_rb_time_nano_new, 2); + rb_define_method(cls, "rb_time_num_new", time_spec_rb_time_num_new, 2); + rb_define_method(cls, "rb_time_interval", time_spec_rb_time_interval, 1); + rb_define_method(cls, "rb_time_timeval", time_spec_rb_time_timeval, 1); + rb_define_method(cls, "rb_time_timespec", time_spec_rb_time_timespec, 1); + rb_define_method(cls, "rb_time_timespec_new", time_spec_rb_time_timespec_new, 3); + rb_define_method(cls, "rb_time_from_timespec", time_spec_rb_time_from_timspec_now, 1); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/tracepoint_spec.c b/spec/ruby/optional/capi/ext/tracepoint_spec.c new file mode 100644 index 0000000000..6666c8f85c --- /dev/null +++ b/spec/ruby/optional/capi/ext/tracepoint_spec.c @@ -0,0 +1,49 @@ +#include "ruby.h" +#include "rubyspec.h" + +#include <ruby/debug.h> + +#ifdef __cplusplus +extern "C" { +#endif + +static VALUE callback_called = Qnil; + +static void callback(VALUE tpval, void *data) { + callback_called = (VALUE) data; +} + +static VALUE tracepoint_spec_rb_tracepoint_new(VALUE self, VALUE data) { + return rb_tracepoint_new(Qnil, RUBY_EVENT_LINE, callback, (void*) data); +} + +static VALUE tracepoint_spec_callback_called(VALUE self) { + return callback_called; +} + +static VALUE tracepoint_spec_rb_tracepoint_disable(VALUE self, VALUE trace) { + rb_tracepoint_disable(trace); + return rb_tracepoint_enabled_p(trace); +} + +static VALUE tracepoint_spec_rb_tracepoint_enable(VALUE self, VALUE trace) { + rb_tracepoint_enable(trace); + return rb_tracepoint_enabled_p(trace); +} + +static VALUE tracepoint_spec_rb_tracepoint_enabled_p(VALUE self, VALUE trace) { + return rb_tracepoint_enabled_p(trace); +} + +void Init_tracepoint_spec(void) { + VALUE cls = rb_define_class("CApiTracePointSpecs", rb_cObject); + rb_define_method(cls, "rb_tracepoint_new", tracepoint_spec_rb_tracepoint_new, 1); + rb_define_method(cls, "rb_tracepoint_disable", tracepoint_spec_rb_tracepoint_disable, 1); + rb_define_method(cls, "rb_tracepoint_enable", tracepoint_spec_rb_tracepoint_enable, 1); + rb_define_method(cls, "rb_tracepoint_enabled_p", tracepoint_spec_rb_tracepoint_enabled_p, 1); + rb_define_method(cls, "callback_called?", tracepoint_spec_callback_called, 0); +} + +#ifdef __cplusplus +} +#endif diff --git a/spec/ruby/optional/capi/ext/typed_data_spec.c b/spec/ruby/optional/capi/ext/typed_data_spec.c new file mode 100644 index 0000000000..221f1c8ac4 --- /dev/null +++ b/spec/ruby/optional/capi/ext/typed_data_spec.c @@ -0,0 +1,203 @@ +#include "ruby.h" +#include "rubyspec.h" + +#include <string.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct sample_typed_wrapped_struct_parent { + int foo; +}; + +void sample_typed_wrapped_struct_parent_free(void* st) { + free(st); +} + +void sample_typed_wrapped_struct_parent_mark(void* st) { +} + +size_t sample_typed_wrapped_struct_parent_memsize(const void* st) { + return sizeof(struct sample_typed_wrapped_struct_parent); +} + +static const rb_data_type_t sample_typed_wrapped_struct_parent_data_type = { + "sample_typed_wrapped_struct_parent", + { + sample_typed_wrapped_struct_parent_mark, + sample_typed_wrapped_struct_parent_free, + sample_typed_wrapped_struct_parent_memsize, + }, +}; + +struct sample_typed_wrapped_struct { + int foo; +}; + +void sample_typed_wrapped_struct_free(void* st) { + free(st); +} + +void sample_typed_wrapped_struct_mark(void* st) { +} + +size_t sample_typed_wrapped_struct_memsize(const void* st) { + if (st == NULL) { + return 0; + } else { + return ((struct sample_typed_wrapped_struct *)st)->foo; + } +} + +static const rb_data_type_t sample_typed_wrapped_struct_data_type = { + "sample_typed_wrapped_struct", + { + sample_typed_wrapped_struct_mark, + sample_typed_wrapped_struct_free, + sample_typed_wrapped_struct_memsize, + }, + &sample_typed_wrapped_struct_parent_data_type, +}; + +struct sample_typed_wrapped_struct_other { + int foo; +}; + +void sample_typed_wrapped_struct_other_free(void* st) { + free(st); +} + +void sample_typed_wrapped_struct_other_mark(void* st) { +} + +size_t sample_typed_wrapped_struct_other_memsize(const void* st) { + return sizeof(struct sample_typed_wrapped_struct_other); +} + +static const rb_data_type_t sample_typed_wrapped_struct_other_data_type = { + "sample_typed_wrapped_struct_other", + { + sample_typed_wrapped_struct_other_mark, + sample_typed_wrapped_struct_other_free, + sample_typed_wrapped_struct_other_memsize, + }, +}; + + +VALUE sdaf_alloc_typed_func(VALUE klass) { + struct sample_typed_wrapped_struct* bar; + bar = (struct sample_typed_wrapped_struct *) malloc(sizeof(struct sample_typed_wrapped_struct)); + bar->foo = 42; + return TypedData_Wrap_Struct(klass, &sample_typed_wrapped_struct_data_type, bar); +} + +VALUE sdaf_typed_get_struct(VALUE self) { + struct sample_typed_wrapped_struct* bar; + TypedData_Get_Struct(self, struct sample_typed_wrapped_struct, &sample_typed_wrapped_struct_data_type, bar); + + return INT2FIX((*bar).foo); +} + +VALUE sws_typed_wrap_struct(VALUE self, VALUE val) { + struct sample_typed_wrapped_struct* bar; + bar = (struct sample_typed_wrapped_struct *) malloc(sizeof(struct sample_typed_wrapped_struct)); + bar->foo = FIX2INT(val); + return TypedData_Wrap_Struct(rb_cObject, &sample_typed_wrapped_struct_data_type, bar); +} + +#undef RUBY_UNTYPED_DATA_WARNING +#define RUBY_UNTYPED_DATA_WARNING 0 +VALUE sws_untyped_wrap_struct(VALUE self, VALUE val) { + int* data = (int*) malloc(sizeof(int)); + *data = FIX2INT(val); + return Data_Wrap_Struct(rb_cObject, NULL, free, data); +} + +VALUE sws_typed_get_struct(VALUE self, VALUE obj) { + struct sample_typed_wrapped_struct* bar; + TypedData_Get_Struct(obj, struct sample_typed_wrapped_struct, &sample_typed_wrapped_struct_data_type, bar); + + return INT2FIX((*bar).foo); +} + +VALUE sws_typed_get_struct_different_type(VALUE self, VALUE obj) { + struct sample_typed_wrapped_struct_other* bar; + TypedData_Get_Struct(obj, struct sample_typed_wrapped_struct_other, &sample_typed_wrapped_struct_other_data_type, bar); + + return INT2FIX((*bar).foo); +} + +VALUE sws_typed_get_struct_parent_type(VALUE self, VALUE obj) { + struct sample_typed_wrapped_struct_parent* bar; + TypedData_Get_Struct(obj, struct sample_typed_wrapped_struct_parent, &sample_typed_wrapped_struct_parent_data_type, bar); + + return INT2FIX((*bar).foo); +} + +VALUE sws_typed_get_struct_rdata(VALUE self, VALUE obj) { + struct sample_typed_wrapped_struct* bar; + bar = (struct sample_typed_wrapped_struct*) RTYPEDDATA(obj)->data; + return INT2FIX(bar->foo); +} + +VALUE sws_typed_get_struct_data_ptr(VALUE self, VALUE obj) { + struct sample_typed_wrapped_struct* bar; + bar = (struct sample_typed_wrapped_struct*) DATA_PTR(obj); + return INT2FIX(bar->foo); +} + +VALUE sws_typed_change_struct(VALUE self, VALUE obj, VALUE new_val) { + struct sample_typed_wrapped_struct *new_struct; + new_struct = (struct sample_typed_wrapped_struct *) malloc(sizeof(struct sample_typed_wrapped_struct)); + new_struct->foo = FIX2INT(new_val); + free(RTYPEDDATA(obj)->data); + RTYPEDDATA(obj)->data = new_struct; + return Qnil; +} + +VALUE sws_typed_rb_check_type(VALUE self, VALUE obj, VALUE other) { + rb_check_type(obj, TYPE(other)); + return Qtrue; +} + +VALUE sws_typed_rb_check_typeddata_same_type(VALUE self, VALUE obj) { + return rb_check_typeddata(obj, &sample_typed_wrapped_struct_data_type) == DATA_PTR(obj) ? Qtrue : Qfalse; +} + +VALUE sws_typed_rb_check_typeddata_same_type_parent(VALUE self, VALUE obj) { + return rb_check_typeddata(obj, &sample_typed_wrapped_struct_parent_data_type) == DATA_PTR(obj) ? Qtrue : Qfalse; +} + +VALUE sws_typed_rb_check_typeddata_different_type(VALUE self, VALUE obj) { + return rb_check_typeddata(obj, &sample_typed_wrapped_struct_other_data_type) == DATA_PTR(obj) ? Qtrue : Qfalse; +} + +VALUE sws_typed_RTYPEDDATA_P(VALUE self, VALUE obj) { + return RTYPEDDATA_P(obj) ? Qtrue : Qfalse; +} + +void Init_typed_data_spec(void) { + VALUE cls = rb_define_class("CApiAllocTypedSpecs", rb_cObject); + rb_define_alloc_func(cls, sdaf_alloc_typed_func); + rb_define_method(cls, "typed_wrapped_data", sdaf_typed_get_struct, 0); + cls = rb_define_class("CApiWrappedTypedStructSpecs", rb_cObject); + rb_define_method(cls, "typed_wrap_struct", sws_typed_wrap_struct, 1); + rb_define_method(cls, "untyped_wrap_struct", sws_untyped_wrap_struct, 1); + rb_define_method(cls, "typed_get_struct", sws_typed_get_struct, 1); + rb_define_method(cls, "typed_get_struct_other", sws_typed_get_struct_different_type, 1); + rb_define_method(cls, "typed_get_struct_parent", sws_typed_get_struct_parent_type, 1); + rb_define_method(cls, "typed_get_struct_rdata", sws_typed_get_struct_rdata, 1); + rb_define_method(cls, "typed_get_struct_data_ptr", sws_typed_get_struct_data_ptr, 1); + rb_define_method(cls, "typed_change_struct", sws_typed_change_struct, 2); + rb_define_method(cls, "rb_check_type", sws_typed_rb_check_type, 2); + rb_define_method(cls, "rb_check_typeddata_same_type", sws_typed_rb_check_typeddata_same_type, 1); + rb_define_method(cls, "rb_check_typeddata_same_type_parent", sws_typed_rb_check_typeddata_same_type_parent, 1); + rb_define_method(cls, "rb_check_typeddata_different_type", sws_typed_rb_check_typeddata_different_type, 1); + rb_define_method(cls, "RTYPEDDATA_P", sws_typed_RTYPEDDATA_P, 1); +} + +#ifdef __cplusplus +} +#endif + diff --git a/spec/ruby/optional/capi/ext/util_spec.c b/spec/ruby/optional/capi/ext/util_spec.c new file mode 100644 index 0000000000..b5bde420d2 --- /dev/null +++ b/spec/ruby/optional/capi/ext/util_spec.c @@ -0,0 +1,121 @@ +#include "ruby.h" +#include "ruby/util.h" +#include "rubyspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +VALUE util_spec_rb_scan_args(VALUE self, VALUE argv, VALUE fmt, VALUE expected, VALUE acc) { + int result, argc; + VALUE a1, a2, a3, a4, a5, a6; + + argc = (int) RARRAY_LEN(argv); + VALUE* args = RARRAY_PTR(argv); + /* the line above can be replaced with this for Ruby implementations which do not support RARRAY_PTR() yet + VALUE args[6]; + for(int i = 0; i < argc; i++) { + args[i] = rb_ary_entry(argv, i); + } */ + + a1 = a2 = a3 = a4 = a5 = a6 = INT2FIX(-1); + +#ifdef RB_SCAN_ARGS_KEYWORDS + if (*RSTRING_PTR(fmt) == 'k') { + result = rb_scan_args_kw(RB_SCAN_ARGS_KEYWORDS, argc, args, RSTRING_PTR(fmt)+1, &a1, &a2, &a3, &a4, &a5, &a6); + } else { +#endif + result = rb_scan_args(argc, args, RSTRING_PTR(fmt), &a1, &a2, &a3, &a4, &a5, &a6); +#ifdef RB_SCAN_ARGS_KEYWORDS + } +#endif + + switch(NUM2INT(expected)) { + case 6: + rb_ary_unshift(acc, a6); + /* FALLTHROUGH */ + case 5: + rb_ary_unshift(acc, a5); + /* FALLTHROUGH */ + case 4: + rb_ary_unshift(acc, a4); + /* FALLTHROUGH */ + case 3: + rb_ary_unshift(acc, a3); + /* FALLTHROUGH */ + case 2: + rb_ary_unshift(acc, a2); + /* FALLTHROUGH */ + case 1: + rb_ary_unshift(acc, a1); + break; + default: + rb_raise(rb_eException, "unexpected number of arguments returned by rb_scan_args"); + } + + return INT2NUM(result); +} + +static VALUE util_spec_rb_get_kwargs(VALUE self, VALUE keyword_hash, VALUE keys, VALUE required, VALUE optional) { + int req = FIX2INT(required); + int opt = FIX2INT(optional); + int len = RARRAY_LENINT(keys); + + int values_len = req + (opt < 0 ? -1 - opt : opt); + + ID *ids = (ID *)alloca(sizeof(VALUE) * len); + VALUE *results = (VALUE *)alloca(sizeof(VALUE) * values_len); + + for (int i = 0; i < len; i++) { + ids[i] = SYM2ID(rb_ary_entry(keys, i)); + } + + int extracted = rb_get_kwargs(keyword_hash, ids, req, opt, results); + + return rb_ary_new_from_values(extracted, results); +} + +static VALUE util_spec_rb_long2int(VALUE self, VALUE n) { + return INT2NUM(rb_long2int(NUM2LONG(n))); +} + +static VALUE util_spec_rb_iter_break(VALUE self) { + rb_iter_break(); + return Qnil; +} + +static VALUE util_spec_rb_sourcefile(VALUE self) { + return rb_str_new2(rb_sourcefile()); +} + +static VALUE util_spec_rb_sourceline(VALUE self) { + return INT2NUM(rb_sourceline()); +} + +static VALUE util_spec_strtod(VALUE self, VALUE string) { + char *endptr = NULL; + double value = strtod(RSTRING_PTR(string), &endptr); + return rb_ary_new_from_args(2, rb_float_new(value), endptr ? rb_str_new2(endptr) : Qnil); +} + +static VALUE util_spec_ruby_strtod(VALUE self, VALUE string) { + char *endptr = NULL; + double value = ruby_strtod(RSTRING_PTR(string), &endptr); + return rb_ary_new_from_args(2, rb_float_new(value), endptr ? rb_str_new2(endptr) : Qnil); +} + +void Init_util_spec(void) { + VALUE cls = rb_define_class("CApiUtilSpecs", rb_cObject); + rb_define_method(cls, "rb_scan_args", util_spec_rb_scan_args, 4); + rb_define_method(cls, "rb_get_kwargs", util_spec_rb_get_kwargs, 4); + rb_define_method(cls, "rb_long2int", util_spec_rb_long2int, 1); + rb_define_method(cls, "rb_iter_break", util_spec_rb_iter_break, 0); + rb_define_method(cls, "rb_sourcefile", util_spec_rb_sourcefile, 0); + rb_define_method(cls, "rb_sourceline", util_spec_rb_sourceline, 0); + rb_define_method(cls, "strtod", util_spec_strtod, 1); + rb_define_method(cls, "ruby_strtod", util_spec_ruby_strtod, 1); +} + +#ifdef __cplusplus +} +#endif |
