Skip to content

Commit ae7b535

Browse files
committed
[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. ruby/fiddle@0ffcaa39e5
1 parent 64926d5 commit ae7b535

File tree

8 files changed

+121
-29
lines changed

8 files changed

+121
-29
lines changed

ext/fiddle/conversions.c

Lines changed: 53 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#include <fiddle.h>
22

33
ffi_type *
4-
int_to_ffi_type(int type)
4+
rb_fiddle_int_to_ffi_type(int type)
55
{
66
int signed_p = 1;
77

@@ -33,66 +33,90 @@ int_to_ffi_type(int type)
3333
return &ffi_type_float;
3434
case TYPE_DOUBLE:
3535
return &ffi_type_double;
36+
case TYPE_CONST_STRING:
37+
return &ffi_type_pointer;
3638
default:
3739
rb_raise(rb_eRuntimeError, "unknown type %d", type);
3840
}
3941
return &ffi_type_pointer;
4042
}
4143

44+
ffi_type *
45+
int_to_ffi_type(int type)
46+
{
47+
return rb_fiddle_int_to_ffi_type(type);
48+
}
49+
4250
void
43-
value_to_generic(int type, VALUE src, fiddle_generic * dst)
51+
rb_fiddle_value_to_generic(int type, VALUE *src, fiddle_generic *dst)
4452
{
4553
switch (type) {
4654
case TYPE_VOID:
4755
break;
4856
case TYPE_VOIDP:
49-
dst->pointer = NUM2PTR(rb_Integer(src));
57+
dst->pointer = NUM2PTR(rb_Integer(*src));
5058
break;
5159
case TYPE_CHAR:
52-
dst->schar = (signed char)NUM2INT(src);
60+
dst->schar = (signed char)NUM2INT(*src);
5361
break;
5462
case -TYPE_CHAR:
55-
dst->uchar = (unsigned char)NUM2UINT(src);
63+
dst->uchar = (unsigned char)NUM2UINT(*src);
5664
break;
5765
case TYPE_SHORT:
58-
dst->sshort = (unsigned short)NUM2INT(src);
66+
dst->sshort = (unsigned short)NUM2INT(*src);
5967
break;
6068
case -TYPE_SHORT:
61-
dst->sshort = (signed short)NUM2UINT(src);
69+
dst->sshort = (signed short)NUM2UINT(*src);
6270
break;
6371
case TYPE_INT:
64-
dst->sint = NUM2INT(src);
72+
dst->sint = NUM2INT(*src);
6573
break;
6674
case -TYPE_INT:
67-
dst->uint = NUM2UINT(src);
75+
dst->uint = NUM2UINT(*src);
6876
break;
6977
case TYPE_LONG:
70-
dst->slong = NUM2LONG(src);
78+
dst->slong = NUM2LONG(*src);
7179
break;
7280
case -TYPE_LONG:
73-
dst->ulong = NUM2ULONG(src);
81+
dst->ulong = NUM2ULONG(*src);
7482
break;
7583
#if HAVE_LONG_LONG
7684
case TYPE_LONG_LONG:
77-
dst->slong_long = NUM2LL(src);
85+
dst->slong_long = NUM2LL(*src);
7886
break;
7987
case -TYPE_LONG_LONG:
80-
dst->ulong_long = NUM2ULL(src);
88+
dst->ulong_long = NUM2ULL(*src);
8189
break;
8290
#endif
8391
case TYPE_FLOAT:
84-
dst->ffloat = (float)NUM2DBL(src);
92+
dst->ffloat = (float)NUM2DBL(*src);
8593
break;
8694
case TYPE_DOUBLE:
87-
dst->ddouble = NUM2DBL(src);
95+
dst->ddouble = NUM2DBL(*src);
96+
break;
97+
case TYPE_CONST_STRING:
98+
if (NIL_P(*src)) {
99+
dst->pointer = NULL;
100+
}
101+
else {
102+
dst->pointer = rb_string_value_cstr(src);
103+
}
88104
break;
89105
default:
90106
rb_raise(rb_eRuntimeError, "unknown type %d", type);
91107
}
92108
}
93109

110+
void
111+
value_to_generic(int type, VALUE src, fiddle_generic *dst)
112+
{
113+
/* src isn't safe from GC when type is TYPE_CONST_STRING and src
114+
* isn't String. */
115+
return rb_fiddle_value_to_generic(type, &src, dst);
116+
}
117+
94118
VALUE
95-
generic_to_value(VALUE rettype, fiddle_generic retval)
119+
rb_fiddle_generic_to_value(VALUE rettype, fiddle_generic retval)
96120
{
97121
int type = NUM2INT(rettype);
98122
VALUE cPointer;
@@ -131,11 +155,24 @@ generic_to_value(VALUE rettype, fiddle_generic retval)
131155
return rb_float_new(retval.ffloat);
132156
case TYPE_DOUBLE:
133157
return rb_float_new(retval.ddouble);
158+
case TYPE_CONST_STRING:
159+
if (retval.pointer) {
160+
return rb_str_new_cstr(retval.pointer);
161+
}
162+
else {
163+
return Qnil;
164+
}
134165
default:
135166
rb_raise(rb_eRuntimeError, "unknown type %d", type);
136167
}
137168

138169
UNREACHABLE;
139170
}
140171

172+
VALUE
173+
generic_to_value(VALUE rettype, fiddle_generic retval)
174+
{
175+
return rb_fiddle_generic_to_value(rettype, retval);
176+
}
177+
141178
/* vim: set noet sw=4 sts=4 */

ext/fiddle/conversions.h

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,22 @@ typedef union
2424
void * pointer; /* ffi_type_pointer */
2525
} fiddle_generic;
2626

27+
/* Deprecated. Use rb_fiddle_*() version. */
28+
ffi_type * rb_fiddle_int_to_ffi_type(int type);
29+
void rb_fiddle_value_to_generic(int type, VALUE *src, fiddle_generic *dst);
30+
VALUE rb_fiddle_generic_to_value(VALUE rettype, fiddle_generic retval);
31+
32+
/* Deprecated. Use rb_fiddle_*() version. */
2733
ffi_type * int_to_ffi_type(int type);
28-
void value_to_generic(int type, VALUE src, fiddle_generic * dst);
34+
void value_to_generic(int type, VALUE src, fiddle_generic *dst);
2935
VALUE generic_to_value(VALUE rettype, fiddle_generic retval);
3036

31-
#define VALUE2GENERIC(_type, _src, _dst) value_to_generic((_type), (_src), (_dst))
32-
#define INT2FFI_TYPE(_type) int_to_ffi_type(_type)
33-
#define GENERIC2VALUE(_type, _retval) generic_to_value((_type), (_retval))
37+
#define VALUE2GENERIC(_type, _src, _dst) \
38+
rb_fiddle_value_to_generic((_type), &(_src), (_dst))
39+
#define INT2FFI_TYPE(_type) \
40+
rb_fiddle_int_to_ffi_type(_type)
41+
#define GENERIC2VALUE(_type, _retval) \
42+
rb_fiddle_generic_to_value((_type), (_retval))
3443

3544
#if SIZEOF_VOIDP == SIZEOF_LONG
3645
# define PTR2NUM(x) (LONG2NUM((long)(x)))

ext/fiddle/fiddle.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,12 @@ Init_fiddle(void)
235235
rb_define_const(mFiddle, "TYPE_VARIADIC", INT2NUM(TYPE_VARIADIC));
236236
#endif
237237

238+
/* Document-const: TYPE_CONST_STRING
239+
*
240+
* C type - const char* ('\0' terminated const char*)
241+
*/
242+
rb_define_const(mFiddle, "TYPE_CONST_STRING", INT2NUM(TYPE_CONST_STRING));
243+
238244
/* Document-const: TYPE_SIZE_T
239245
*
240246
* C type - size_t
@@ -435,6 +441,12 @@ Init_fiddle(void)
435441
*/
436442
rb_define_const(mFiddle, "SIZEOF_UINTPTR_T", INT2NUM(sizeof(uintptr_t)));
437443

444+
/* Document-const: SIZEOF_CONST_STRING
445+
*
446+
* size of a const char*
447+
*/
448+
rb_define_const(mFiddle, "SIZEOF_CONST_STRING", INT2NUM(sizeof(const char*)));
449+
438450
/* Document-const: RUBY_FREE
439451
*
440452
* Address of the ruby_xfree() function

ext/fiddle/fiddle.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@
116116
#define TYPE_FLOAT 7
117117
#define TYPE_DOUBLE 8
118118
#define TYPE_VARIADIC 9
119+
#define TYPE_CONST_STRING 10
119120

120121
#define ALIGN_OF(type) offsetof(struct {char align_c; type align_x;}, align_x)
121122

ext/fiddle/function.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ function_call(int argc, VALUE argv[], VALUE self)
207207
int n_call_args = 0;
208208
int i;
209209
int i_call;
210+
VALUE converted_args = Qnil;
210211
VALUE alloc_buffer = 0;
211212

212213
cfunc = rb_iv_get(self, "@ptr");
@@ -313,6 +314,7 @@ function_call(int argc, VALUE argv[], VALUE self)
313314
i++, i_call++) {
314315
VALUE arg_type;
315316
int c_arg_type;
317+
VALUE original_src;
316318
VALUE src;
317319
arg_type = RARRAY_AREF(arg_types, i_call);
318320
c_arg_type = FIX2INT(arg_type);
@@ -327,11 +329,22 @@ function_call(int argc, VALUE argv[], VALUE self)
327329
}
328330
else if (cPointer != CLASS_OF(src)) {
329331
src = rb_funcall(cPointer, rb_intern("[]"), 1, src);
332+
if (NIL_P(converted_args)) {
333+
converted_args = rb_ary_new();
334+
}
335+
rb_ary_push(converted_args, src);
330336
}
331337
src = rb_Integer(src);
332338
}
333339

340+
original_src = src;
334341
VALUE2GENERIC(c_arg_type, src, &generic_args[i_call]);
342+
if (src != original_src) {
343+
if (NIL_P(converted_args)) {
344+
converted_args = rb_ary_new();
345+
}
346+
rb_ary_push(converted_args, src);
347+
}
335348
args.values[i_call] = (void *)&generic_args[i_call];
336349
}
337350
args.values[i_call] = NULL;

ext/fiddle/lib/fiddle/import.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ def sizeof(ty)
121121
return SIZEOF_DOUBLE
122122
when TYPE_VOIDP
123123
return SIZEOF_VOIDP
124+
when TYPE_CONST_STRING
125+
return SIZEOF_CONST_STRING
124126
else
125127
if defined?(TYPE_LONG_LONG) and
126128
ty == TYPE_LONG_LONG

test/fiddle/test_func.rb

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ def test_snprintf
9898
[
9999
TYPE_VOIDP,
100100
TYPE_SIZE_T,
101-
TYPE_VOIDP,
101+
TYPE_CONST_STRING,
102102
TYPE_VARIADIC,
103103
],
104104
TYPE_INT)
@@ -107,20 +107,31 @@ def test_snprintf
107107

108108
written = snprintf.call(output,
109109
output.size,
110-
"int: %d, string: %.*s\n",
110+
"int: %d, string: %.*s, const string: %s\n",
111111
TYPE_INT, -29,
112112
TYPE_INT, 4,
113-
TYPE_VOIDP, "Hello")
114-
assert_equal("int: -29, string: Hell\n",
113+
TYPE_VOIDP, "Hello",
114+
TYPE_CONST_STRING, "World")
115+
assert_equal("int: -29, string: Hell, const string: World\n",
115116
output_buffer[0, written])
116117

118+
string_like_class = Class.new do
119+
def initialize(string)
120+
@string = string
121+
end
122+
123+
def to_str
124+
@string
125+
end
126+
end
117127
written = snprintf.call(output,
118128
output.size,
119-
"string: %.*s, uint: %u\n",
129+
"string: %.*s, const string: %s, uint: %u\n",
120130
TYPE_INT, 2,
121131
TYPE_VOIDP, "Hello",
132+
TYPE_CONST_STRING, string_like_class.new("World"),
122133
TYPE_INT, 29)
123-
assert_equal("string: He, uint: 29\n",
134+
assert_equal("string: He, const string: World, uint: 29\n",
124135
output_buffer[0, written])
125136
end
126137
end

test/fiddle/test_import.rb

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,17 @@ def test_sizeof()
112112

113113
Fiddle.constants.grep(/\ATYPE_(?!VOID|VARIADIC\z)(.*)/) do
114114
type = $&
115-
size = Fiddle.const_get("SIZEOF_#{$1}")
116-
name = $1.sub(/P\z/,"*").gsub(/_(?!T\z)/, " ").downcase
115+
const_type_name = $1
116+
size = Fiddle.const_get("SIZEOF_#{const_type_name}")
117+
if const_type_name == "CONST_STRING"
118+
name = "const_string"
119+
type_name = "const char*"
120+
else
121+
name = $1.sub(/P\z/,"*").gsub(/_(?!T\z)/, " ").downcase
122+
type_name = name
123+
end
117124
define_method("test_sizeof_#{name}") do
118-
assert_equal(size, Fiddle::Importer.sizeof(name), type)
125+
assert_equal(size, Fiddle::Importer.sizeof(type_name), type)
119126
end
120127
end
121128

0 commit comments

Comments
 (0)