1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

[ruby/fiddle] Add TYPE_CONST_STRING and SIZEOF_CONST_STRING for "const char *"

Add rb_fiddle_ prefix to conversion functions.h to keep backward
compatibility but value_to_generic() isn't safe for TYPE_CONST_STRING
and not String src. Use rb_fiddle_value_to_generic() instead.

https://github.com/ruby/fiddle/commit/0ffcaa39e5
This commit is contained in:
Sutou Kouhei 2020-07-09 20:19:20 +09:00 committed by Sutou Kouhei
parent 64926d5007
commit ae7b53546c
Notes: git 2020-11-18 09:05:47 +09:00
8 changed files with 121 additions and 29 deletions

View file

@ -1,7 +1,7 @@
#include <fiddle.h>
ffi_type *
int_to_ffi_type(int type)
rb_fiddle_int_to_ffi_type(int type)
{
int signed_p = 1;
@ -33,66 +33,90 @@ int_to_ffi_type(int type)
return &ffi_type_float;
case TYPE_DOUBLE:
return &ffi_type_double;
case TYPE_CONST_STRING:
return &ffi_type_pointer;
default:
rb_raise(rb_eRuntimeError, "unknown type %d", type);
}
return &ffi_type_pointer;
}
ffi_type *
int_to_ffi_type(int type)
{
return rb_fiddle_int_to_ffi_type(type);
}
void
value_to_generic(int type, VALUE src, fiddle_generic * dst)
rb_fiddle_value_to_generic(int type, VALUE *src, fiddle_generic *dst)
{
switch (type) {
case TYPE_VOID:
break;
case TYPE_VOIDP:
dst->pointer = NUM2PTR(rb_Integer(src));
dst->pointer = NUM2PTR(rb_Integer(*src));
break;
case TYPE_CHAR:
dst->schar = (signed char)NUM2INT(src);
dst->schar = (signed char)NUM2INT(*src);
break;
case -TYPE_CHAR:
dst->uchar = (unsigned char)NUM2UINT(src);
dst->uchar = (unsigned char)NUM2UINT(*src);
break;
case TYPE_SHORT:
dst->sshort = (unsigned short)NUM2INT(src);
dst->sshort = (unsigned short)NUM2INT(*src);
break;
case -TYPE_SHORT:
dst->sshort = (signed short)NUM2UINT(src);
dst->sshort = (signed short)NUM2UINT(*src);
break;
case TYPE_INT:
dst->sint = NUM2INT(src);
dst->sint = NUM2INT(*src);
break;
case -TYPE_INT:
dst->uint = NUM2UINT(src);
dst->uint = NUM2UINT(*src);
break;
case TYPE_LONG:
dst->slong = NUM2LONG(src);
dst->slong = NUM2LONG(*src);
break;
case -TYPE_LONG:
dst->ulong = NUM2ULONG(src);
dst->ulong = NUM2ULONG(*src);
break;
#if HAVE_LONG_LONG
case TYPE_LONG_LONG:
dst->slong_long = NUM2LL(src);
dst->slong_long = NUM2LL(*src);
break;
case -TYPE_LONG_LONG:
dst->ulong_long = NUM2ULL(src);
dst->ulong_long = NUM2ULL(*src);
break;
#endif
case TYPE_FLOAT:
dst->ffloat = (float)NUM2DBL(src);
dst->ffloat = (float)NUM2DBL(*src);
break;
case TYPE_DOUBLE:
dst->ddouble = NUM2DBL(src);
dst->ddouble = NUM2DBL(*src);
break;
case TYPE_CONST_STRING:
if (NIL_P(*src)) {
dst->pointer = NULL;
}
else {
dst->pointer = rb_string_value_cstr(src);
}
break;
default:
rb_raise(rb_eRuntimeError, "unknown type %d", type);
}
}
void
value_to_generic(int type, VALUE src, fiddle_generic *dst)
{
/* src isn't safe from GC when type is TYPE_CONST_STRING and src
* isn't String. */
return rb_fiddle_value_to_generic(type, &src, dst);
}
VALUE
generic_to_value(VALUE rettype, fiddle_generic retval)
rb_fiddle_generic_to_value(VALUE rettype, fiddle_generic retval)
{
int type = NUM2INT(rettype);
VALUE cPointer;
@ -131,6 +155,13 @@ generic_to_value(VALUE rettype, fiddle_generic retval)
return rb_float_new(retval.ffloat);
case TYPE_DOUBLE:
return rb_float_new(retval.ddouble);
case TYPE_CONST_STRING:
if (retval.pointer) {
return rb_str_new_cstr(retval.pointer);
}
else {
return Qnil;
}
default:
rb_raise(rb_eRuntimeError, "unknown type %d", type);
}
@ -138,4 +169,10 @@ generic_to_value(VALUE rettype, fiddle_generic retval)
UNREACHABLE;
}
VALUE
generic_to_value(VALUE rettype, fiddle_generic retval)
{
return rb_fiddle_generic_to_value(rettype, retval);
}
/* vim: set noet sw=4 sts=4 */

View file

@ -24,13 +24,22 @@ typedef union
void * pointer; /* ffi_type_pointer */
} fiddle_generic;
/* Deprecated. Use rb_fiddle_*() version. */
ffi_type * rb_fiddle_int_to_ffi_type(int type);
void rb_fiddle_value_to_generic(int type, VALUE *src, fiddle_generic *dst);
VALUE rb_fiddle_generic_to_value(VALUE rettype, fiddle_generic retval);
/* Deprecated. Use rb_fiddle_*() version. */
ffi_type * int_to_ffi_type(int type);
void value_to_generic(int type, VALUE src, fiddle_generic *dst);
VALUE generic_to_value(VALUE rettype, fiddle_generic retval);
#define VALUE2GENERIC(_type, _src, _dst) value_to_generic((_type), (_src), (_dst))
#define INT2FFI_TYPE(_type) int_to_ffi_type(_type)
#define GENERIC2VALUE(_type, _retval) generic_to_value((_type), (_retval))
#define VALUE2GENERIC(_type, _src, _dst) \
rb_fiddle_value_to_generic((_type), &(_src), (_dst))
#define INT2FFI_TYPE(_type) \
rb_fiddle_int_to_ffi_type(_type)
#define GENERIC2VALUE(_type, _retval) \
rb_fiddle_generic_to_value((_type), (_retval))
#if SIZEOF_VOIDP == SIZEOF_LONG
# define PTR2NUM(x) (LONG2NUM((long)(x)))

View file

@ -235,6 +235,12 @@ Init_fiddle(void)
rb_define_const(mFiddle, "TYPE_VARIADIC", INT2NUM(TYPE_VARIADIC));
#endif
/* Document-const: TYPE_CONST_STRING
*
* C type - const char* ('\0' terminated const char*)
*/
rb_define_const(mFiddle, "TYPE_CONST_STRING", INT2NUM(TYPE_CONST_STRING));
/* Document-const: TYPE_SIZE_T
*
* C type - size_t
@ -435,6 +441,12 @@ Init_fiddle(void)
*/
rb_define_const(mFiddle, "SIZEOF_UINTPTR_T", INT2NUM(sizeof(uintptr_t)));
/* Document-const: SIZEOF_CONST_STRING
*
* size of a const char*
*/
rb_define_const(mFiddle, "SIZEOF_CONST_STRING", INT2NUM(sizeof(const char*)));
/* Document-const: RUBY_FREE
*
* Address of the ruby_xfree() function

View file

@ -116,6 +116,7 @@
#define TYPE_FLOAT 7
#define TYPE_DOUBLE 8
#define TYPE_VARIADIC 9
#define TYPE_CONST_STRING 10
#define ALIGN_OF(type) offsetof(struct {char align_c; type align_x;}, align_x)

View file

@ -207,6 +207,7 @@ function_call(int argc, VALUE argv[], VALUE self)
int n_call_args = 0;
int i;
int i_call;
VALUE converted_args = Qnil;
VALUE alloc_buffer = 0;
cfunc = rb_iv_get(self, "@ptr");
@ -313,6 +314,7 @@ function_call(int argc, VALUE argv[], VALUE self)
i++, i_call++) {
VALUE arg_type;
int c_arg_type;
VALUE original_src;
VALUE src;
arg_type = RARRAY_AREF(arg_types, i_call);
c_arg_type = FIX2INT(arg_type);
@ -327,11 +329,22 @@ function_call(int argc, VALUE argv[], VALUE self)
}
else if (cPointer != CLASS_OF(src)) {
src = rb_funcall(cPointer, rb_intern("[]"), 1, src);
if (NIL_P(converted_args)) {
converted_args = rb_ary_new();
}
rb_ary_push(converted_args, src);
}
src = rb_Integer(src);
}
original_src = src;
VALUE2GENERIC(c_arg_type, src, &generic_args[i_call]);
if (src != original_src) {
if (NIL_P(converted_args)) {
converted_args = rb_ary_new();
}
rb_ary_push(converted_args, src);
}
args.values[i_call] = (void *)&generic_args[i_call];
}
args.values[i_call] = NULL;

View file

@ -121,6 +121,8 @@ module Fiddle
return SIZEOF_DOUBLE
when TYPE_VOIDP
return SIZEOF_VOIDP
when TYPE_CONST_STRING
return SIZEOF_CONST_STRING
else
if defined?(TYPE_LONG_LONG) and
ty == TYPE_LONG_LONG

View file

@ -98,7 +98,7 @@ module Fiddle
[
TYPE_VOIDP,
TYPE_SIZE_T,
TYPE_VOIDP,
TYPE_CONST_STRING,
TYPE_VARIADIC,
],
TYPE_INT)
@ -107,20 +107,31 @@ module Fiddle
written = snprintf.call(output,
output.size,
"int: %d, string: %.*s\n",
"int: %d, string: %.*s, const string: %s\n",
TYPE_INT, -29,
TYPE_INT, 4,
TYPE_VOIDP, "Hello")
assert_equal("int: -29, string: Hell\n",
TYPE_VOIDP, "Hello",
TYPE_CONST_STRING, "World")
assert_equal("int: -29, string: Hell, const string: World\n",
output_buffer[0, written])
string_like_class = Class.new do
def initialize(string)
@string = string
end
def to_str
@string
end
end
written = snprintf.call(output,
output.size,
"string: %.*s, uint: %u\n",
"string: %.*s, const string: %s, uint: %u\n",
TYPE_INT, 2,
TYPE_VOIDP, "Hello",
TYPE_CONST_STRING, string_like_class.new("World"),
TYPE_INT, 29)
assert_equal("string: He, uint: 29\n",
assert_equal("string: He, const string: World, uint: 29\n",
output_buffer[0, written])
end
end

View file

@ -112,10 +112,17 @@ module Fiddle
Fiddle.constants.grep(/\ATYPE_(?!VOID|VARIADIC\z)(.*)/) do
type = $&
size = Fiddle.const_get("SIZEOF_#{$1}")
const_type_name = $1
size = Fiddle.const_get("SIZEOF_#{const_type_name}")
if const_type_name == "CONST_STRING"
name = "const_string"
type_name = "const char*"
else
name = $1.sub(/P\z/,"*").gsub(/_(?!T\z)/, " ").downcase
type_name = name
end
define_method("test_sizeof_#{name}") do
assert_equal(size, Fiddle::Importer.sizeof(name), type)
assert_equal(size, Fiddle::Importer.sizeof(type_name), type)
end
end