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:
parent
64926d5007
commit
ae7b53546c
Notes:
git
2020-11-18 09:05:47 +09:00
8 changed files with 121 additions and 29 deletions
|
@ -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 */
|
||||
|
|
|
@ -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)))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in a new issue