fiddle 1.0.6 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/Rakefile +12 -0
- data/ext/fiddle/closure.c +20 -6
- data/ext/fiddle/conversions.h +0 -1
- data/ext/fiddle/extconf.rb +47 -5
- data/ext/fiddle/fiddle.c +2 -2
- data/ext/fiddle/fiddle.h +7 -4
- data/ext/fiddle/function.c +10 -2
- data/ext/fiddle/handle.c +59 -1
- data/ext/fiddle/memory_view.c +78 -11
- data/ext/fiddle/pointer.c +18 -9
- data/fiddle.gemspec +1 -5
- data/lib/fiddle/cparser.rb +4 -2
- data/lib/fiddle/function.rb +6 -0
- data/lib/fiddle/struct.rb +71 -0
- data/lib/fiddle/types.rb +18 -17
- data/lib/fiddle/version.rb +1 -1
- data/lib/fiddle.rb +12 -0
- metadata +5 -47
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 53ccf1d87df1a91951377a4baf37bf13519b15a05dd4ae6f18789027ffa69a44
|
4
|
+
data.tar.gz: 59c667cd8a70043e46e517b77700565e481d0ea69c8f7e85a5a27f98914ed357
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a10f7c91bde1fe0b9d9c1cc57a0b0ea1c0001e59301496cb676893f0fc948bbae570a8c78ac523a84c43b977db17ff9c2c101e7154ece15ac2b66eb4cf561618
|
7
|
+
data.tar.gz: 41be31921c03c6a153f24bfda7753c706ad0d68602fc6b59f8fe2ebe4d54282e3c0e029ff327ac2aa17bca9e66ccb593d133b6534bd677169b1a99d16ad8bfc8
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Fiddle
|
2
2
|
|
3
|
-
[![
|
3
|
+
[![CI](https://github.com/ruby/fiddle/actions/workflows/ci.yml/badge.svg)](https://github.com/ruby/fiddle/actions/workflows/ci.yml)
|
4
4
|
|
5
5
|
A libffi wrapper for Ruby.
|
6
6
|
|
data/Rakefile
CHANGED
@@ -5,6 +5,18 @@ task :test do
|
|
5
5
|
ruby("test/run.rb")
|
6
6
|
end
|
7
7
|
|
8
|
+
namespace :version do
|
9
|
+
desc "Bump version"
|
10
|
+
task :bump do
|
11
|
+
version_rb_path = "lib/fiddle/version.rb"
|
12
|
+
version_rb = File.read(version_rb_path).gsub(/VERSION = "(.+?)"/) do
|
13
|
+
version = $1
|
14
|
+
"VERSION = \"#{version.succ}\""
|
15
|
+
end
|
16
|
+
File.write(version_rb_path, version_rb)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
8
20
|
require 'rake/extensiontask'
|
9
21
|
Rake::ExtensionTask.new("fiddle")
|
10
22
|
Rake::ExtensionTask.new("-test-/memory_view")
|
data/ext/fiddle/closure.c
CHANGED
@@ -130,6 +130,10 @@ with_gvl_callback(void *ptr)
|
|
130
130
|
rb_ary_push(params, ULL2NUM(*(unsigned LONG_LONG *)x->args[i]));
|
131
131
|
break;
|
132
132
|
#endif
|
133
|
+
case TYPE_CONST_STRING:
|
134
|
+
rb_ary_push(params,
|
135
|
+
rb_str_new_cstr(*((const char **)(x->args[i]))));
|
136
|
+
break;
|
133
137
|
default:
|
134
138
|
rb_raise(rb_eRuntimeError, "closure args: %d", type);
|
135
139
|
}
|
@@ -175,6 +179,10 @@ with_gvl_callback(void *ptr)
|
|
175
179
|
*(unsigned LONG_LONG *)x->resp = NUM2ULL(ret);
|
176
180
|
break;
|
177
181
|
#endif
|
182
|
+
case TYPE_CONST_STRING:
|
183
|
+
/* Dangerous. Callback must keep reference of the String. */
|
184
|
+
*((const char **)(x->resp)) = StringValueCStr(ret);
|
185
|
+
break;
|
178
186
|
default:
|
179
187
|
rb_raise(rb_eRuntimeError, "closure retval: %d", type);
|
180
188
|
}
|
@@ -221,6 +229,7 @@ initialize(int rbargc, VALUE argv[], VALUE self)
|
|
221
229
|
{
|
222
230
|
VALUE ret;
|
223
231
|
VALUE args;
|
232
|
+
VALUE normalized_args;
|
224
233
|
VALUE abi;
|
225
234
|
fiddle_closure * cl;
|
226
235
|
ffi_cif * cif;
|
@@ -239,21 +248,26 @@ initialize(int rbargc, VALUE argv[], VALUE self)
|
|
239
248
|
|
240
249
|
cl->argv = (ffi_type **)xcalloc(argc + 1, sizeof(ffi_type *));
|
241
250
|
|
251
|
+
normalized_args = rb_ary_new_capa(argc);
|
242
252
|
for (i = 0; i < argc; i++) {
|
243
|
-
|
244
|
-
|
253
|
+
VALUE arg = rb_fiddle_type_ensure(RARRAY_AREF(args, i));
|
254
|
+
rb_ary_push(normalized_args, arg);
|
255
|
+
cl->argv[i] = rb_fiddle_int_to_ffi_type(NUM2INT(arg));
|
245
256
|
}
|
246
257
|
cl->argv[argc] = NULL;
|
247
258
|
|
259
|
+
ret = rb_fiddle_type_ensure(ret);
|
248
260
|
rb_iv_set(self, "@ctype", ret);
|
249
|
-
rb_iv_set(self, "@args",
|
261
|
+
rb_iv_set(self, "@args", normalized_args);
|
250
262
|
|
251
263
|
cif = &cl->cif;
|
252
264
|
pcl = cl->pcl;
|
253
265
|
|
254
|
-
result = ffi_prep_cif(cif,
|
255
|
-
|
256
|
-
|
266
|
+
result = ffi_prep_cif(cif,
|
267
|
+
NUM2INT(abi),
|
268
|
+
argc,
|
269
|
+
rb_fiddle_int_to_ffi_type(NUM2INT(ret)),
|
270
|
+
cl->argv);
|
257
271
|
|
258
272
|
if (FFI_OK != result)
|
259
273
|
rb_raise(rb_eRuntimeError, "error prepping CIF %d", result);
|
data/ext/fiddle/conversions.h
CHANGED
@@ -24,7 +24,6 @@ typedef union
|
|
24
24
|
void * pointer; /* ffi_type_pointer */
|
25
25
|
} fiddle_generic;
|
26
26
|
|
27
|
-
/* Deprecated. Use rb_fiddle_*() version. */
|
28
27
|
VALUE rb_fiddle_type_ensure(VALUE type);
|
29
28
|
ffi_type * rb_fiddle_int_to_ffi_type(int type);
|
30
29
|
void rb_fiddle_value_to_generic(int type, VALUE *src, fiddle_generic *dst);
|
data/ext/fiddle/extconf.rb
CHANGED
@@ -3,6 +3,47 @@ require 'mkmf'
|
|
3
3
|
|
4
4
|
# :stopdoc:
|
5
5
|
|
6
|
+
def gcc?
|
7
|
+
RbConfig::CONFIG["GCC"] == "yes"
|
8
|
+
end
|
9
|
+
|
10
|
+
def disable_optimization_build_flag(flags)
|
11
|
+
if gcc?
|
12
|
+
expanded_flags = RbConfig.expand(flags.dup)
|
13
|
+
optimization_option_pattern = /(^|\s)?-O\d(\s|$)?/
|
14
|
+
if optimization_option_pattern.match?(expanded_flags)
|
15
|
+
expanded_flags.gsub(optimization_option_pattern, '\\1-Og\\2')
|
16
|
+
else
|
17
|
+
flags + " -Og"
|
18
|
+
end
|
19
|
+
else
|
20
|
+
flags
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def enable_debug_build_flag(flags)
|
25
|
+
if gcc?
|
26
|
+
expanded_flags = RbConfig.expand(flags.dup)
|
27
|
+
debug_option_pattern = /(^|\s)-g(?:gdb)?\d?(\s|$)/
|
28
|
+
if debug_option_pattern.match?(expanded_flags)
|
29
|
+
expanded_flags.gsub(debug_option_pattern, '\\1-ggdb3\\2')
|
30
|
+
else
|
31
|
+
flags + " -ggdb3"
|
32
|
+
end
|
33
|
+
else
|
34
|
+
flags
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
checking_for(checking_message("--enable-debug-build option")) do
|
39
|
+
enable_debug_build = enable_config("debug-build", false)
|
40
|
+
if enable_debug_build
|
41
|
+
$CFLAGS = disable_optimization_build_flag($CFLAGS)
|
42
|
+
$CFLAGS = enable_debug_build_flag($CFLAGS)
|
43
|
+
end
|
44
|
+
enable_debug_build
|
45
|
+
end
|
46
|
+
|
6
47
|
libffi_version = nil
|
7
48
|
have_libffi = false
|
8
49
|
bundle = enable_config('bundled-libffi')
|
@@ -146,6 +187,7 @@ else
|
|
146
187
|
end
|
147
188
|
|
148
189
|
have_header 'sys/mman.h'
|
190
|
+
have_header 'link.h'
|
149
191
|
|
150
192
|
if have_header "dlfcn.h"
|
151
193
|
have_library "dl"
|
@@ -155,10 +197,14 @@ if have_header "dlfcn.h"
|
|
155
197
|
end
|
156
198
|
|
157
199
|
have_func "dlerror"
|
200
|
+
have_func "dlinfo"
|
201
|
+
have_const("RTLD_DI_LINKMAP", "dlfcn.h")
|
158
202
|
elsif have_header "windows.h"
|
159
|
-
%w{ LoadLibrary FreeLibrary GetProcAddress }.each do |func|
|
203
|
+
%w{ LoadLibrary FreeLibrary GetProcAddress GetModuleFileName }.each do |func|
|
160
204
|
abort "missing function #{func}" unless have_func(func)
|
161
205
|
end
|
206
|
+
|
207
|
+
have_library "ws2_32"
|
162
208
|
end
|
163
209
|
|
164
210
|
have_const('FFI_STDCALL', ffi_header)
|
@@ -179,10 +225,6 @@ types.each do |type, signed|
|
|
179
225
|
end
|
180
226
|
end
|
181
227
|
|
182
|
-
if have_header("ruby/memory_view.h")
|
183
|
-
have_type("rb_memory_view_t", ["ruby/memory_view.h"])
|
184
|
-
end
|
185
|
-
|
186
228
|
if libffi
|
187
229
|
$LOCAL_LIBS.prepend("./#{libffi.a} ").strip! # to exts.mk
|
188
230
|
$INCFLAGS.gsub!(/-I#{libffi.dir}/, '-I$(LIBFFI_DIR)')
|
data/ext/fiddle/fiddle.c
CHANGED
@@ -7,7 +7,7 @@ VALUE rb_eFiddleError;
|
|
7
7
|
void Init_fiddle_pointer(void);
|
8
8
|
void Init_fiddle_pinned(void);
|
9
9
|
|
10
|
-
#ifdef
|
10
|
+
#ifdef HAVE_RUBY_MEMORY_VIEW_H
|
11
11
|
void Init_fiddle_memory_view(void);
|
12
12
|
#endif
|
13
13
|
|
@@ -546,7 +546,7 @@ Init_fiddle(void)
|
|
546
546
|
Init_fiddle_pointer();
|
547
547
|
Init_fiddle_pinned();
|
548
548
|
|
549
|
-
#ifdef
|
549
|
+
#ifdef HAVE_RUBY_MEMORY_VIEW_H
|
550
550
|
Init_fiddle_memory_view();
|
551
551
|
#endif
|
552
552
|
}
|
data/ext/fiddle/fiddle.h
CHANGED
@@ -12,6 +12,10 @@
|
|
12
12
|
#include <sys/mman.h>
|
13
13
|
#endif
|
14
14
|
|
15
|
+
#if defined(HAVE_LINK_H)
|
16
|
+
# include <link.h>
|
17
|
+
#endif
|
18
|
+
|
15
19
|
#if defined(HAVE_DLFCN_H)
|
16
20
|
# include <dlfcn.h>
|
17
21
|
# /* some stranger systems may not define all of these */
|
@@ -189,14 +193,13 @@
|
|
189
193
|
#define ALIGN_INT32_T ALIGN_OF(int32_t)
|
190
194
|
#define ALIGN_INT64_T ALIGN_OF(int64_t)
|
191
195
|
|
192
|
-
#ifdef HAVE_TYPE_RB_MEMORY_VIEW_T
|
193
|
-
# define FIDDLE_MEMORY_VIEW
|
194
|
-
#endif
|
195
|
-
|
196
196
|
extern VALUE mFiddle;
|
197
197
|
extern VALUE rb_eFiddleDLError;
|
198
198
|
|
199
199
|
VALUE rb_fiddle_new_function(VALUE address, VALUE arg_types, VALUE ret_type);
|
200
200
|
|
201
|
+
typedef void (*rb_fiddle_freefunc_t)(void*);
|
202
|
+
VALUE rb_fiddle_ptr_new_wrap(void *ptr, long size, rb_fiddle_freefunc_t func, VALUE wrap0, VALUE wrap1);
|
203
|
+
|
201
204
|
#endif
|
202
205
|
/* vim: set noet sws=4 sw=4: */
|
data/ext/fiddle/function.c
CHANGED
@@ -375,10 +375,18 @@ function_call(int argc, VALUE argv[], VALUE self)
|
|
375
375
|
(void)rb_thread_call_without_gvl(nogvl_ffi_call, &args, 0, 0);
|
376
376
|
}
|
377
377
|
|
378
|
-
|
378
|
+
{
|
379
|
+
int errno_keep = errno;
|
379
380
|
#if defined(_WIN32)
|
380
|
-
|
381
|
+
DWORD error = WSAGetLastError();
|
382
|
+
int socket_error = WSAGetLastError();
|
383
|
+
rb_funcall(mFiddle, rb_intern("win32_last_error="), 1,
|
384
|
+
ULONG2NUM(error));
|
385
|
+
rb_funcall(mFiddle, rb_intern("win32_last_socket_error="), 1,
|
386
|
+
INT2NUM(socket_error));
|
381
387
|
#endif
|
388
|
+
rb_funcall(mFiddle, rb_intern("last_error="), 1, INT2NUM(errno_keep));
|
389
|
+
}
|
382
390
|
|
383
391
|
ALLOCV_END(alloc_buffer);
|
384
392
|
|
data/ext/fiddle/handle.c
CHANGED
@@ -259,7 +259,21 @@ rb_fiddle_handle_to_i(VALUE self)
|
|
259
259
|
struct dl_handle *fiddle_handle;
|
260
260
|
|
261
261
|
TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
|
262
|
-
return PTR2NUM(fiddle_handle);
|
262
|
+
return PTR2NUM(fiddle_handle->ptr);
|
263
|
+
}
|
264
|
+
|
265
|
+
/*
|
266
|
+
* call-seq: to_ptr
|
267
|
+
*
|
268
|
+
* Returns the Fiddle::Pointer of this handle.
|
269
|
+
*/
|
270
|
+
static VALUE
|
271
|
+
rb_fiddle_handle_to_ptr(VALUE self)
|
272
|
+
{
|
273
|
+
struct dl_handle *fiddle_handle;
|
274
|
+
|
275
|
+
TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
|
276
|
+
return rb_fiddle_ptr_new_wrap(fiddle_handle->ptr, 0, 0, self, 0);
|
263
277
|
}
|
264
278
|
|
265
279
|
static VALUE fiddle_handle_sym(void *handle, VALUE symbol);
|
@@ -372,6 +386,48 @@ fiddle_handle_sym(void *handle, VALUE symbol)
|
|
372
386
|
return PTR2NUM(func);
|
373
387
|
}
|
374
388
|
|
389
|
+
/*
|
390
|
+
* call-seq: file_name
|
391
|
+
*
|
392
|
+
* Returns the file name of this handle.
|
393
|
+
*/
|
394
|
+
static VALUE
|
395
|
+
rb_fiddle_handle_file_name(VALUE self)
|
396
|
+
{
|
397
|
+
struct dl_handle *fiddle_handle;
|
398
|
+
|
399
|
+
TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
|
400
|
+
|
401
|
+
#if defined(HAVE_DLINFO) && defined(HAVE_CONST_RTLD_DI_LINKMAP)
|
402
|
+
{
|
403
|
+
struct link_map *lm = NULL;
|
404
|
+
int res = dlinfo(fiddle_handle->ptr, RTLD_DI_LINKMAP, &lm);
|
405
|
+
if (res == 0 && lm != NULL) {
|
406
|
+
return rb_str_new_cstr(lm->l_name);
|
407
|
+
}
|
408
|
+
else {
|
409
|
+
#if defined(HAVE_DLERROR)
|
410
|
+
rb_raise(rb_eFiddleDLError, "could not get handle file name: %s", dlerror());
|
411
|
+
#else
|
412
|
+
rb_raise(rb_eFiddleDLError, "could not get handle file name");
|
413
|
+
#endif
|
414
|
+
}
|
415
|
+
}
|
416
|
+
#elif defined(HAVE_GETMODULEFILENAME)
|
417
|
+
{
|
418
|
+
char filename[MAX_PATH];
|
419
|
+
DWORD res = GetModuleFileName(fiddle_handle->ptr, filename, MAX_PATH);
|
420
|
+
if (res == 0) {
|
421
|
+
rb_raise(rb_eFiddleDLError, "could not get handle file name: %s", dlerror());
|
422
|
+
}
|
423
|
+
return rb_str_new_cstr(filename);
|
424
|
+
}
|
425
|
+
#else
|
426
|
+
(void)fiddle_handle;
|
427
|
+
return Qnil;
|
428
|
+
#endif
|
429
|
+
}
|
430
|
+
|
375
431
|
void
|
376
432
|
Init_fiddle_handle(void)
|
377
433
|
{
|
@@ -466,9 +522,11 @@ Init_fiddle_handle(void)
|
|
466
522
|
|
467
523
|
rb_define_method(rb_cHandle, "initialize", rb_fiddle_handle_initialize, -1);
|
468
524
|
rb_define_method(rb_cHandle, "to_i", rb_fiddle_handle_to_i, 0);
|
525
|
+
rb_define_method(rb_cHandle, "to_ptr", rb_fiddle_handle_to_ptr, 0);
|
469
526
|
rb_define_method(rb_cHandle, "close", rb_fiddle_handle_close, 0);
|
470
527
|
rb_define_method(rb_cHandle, "sym", rb_fiddle_handle_sym, 1);
|
471
528
|
rb_define_method(rb_cHandle, "[]", rb_fiddle_handle_sym, 1);
|
529
|
+
rb_define_method(rb_cHandle, "file_name", rb_fiddle_handle_file_name, 0);
|
472
530
|
rb_define_method(rb_cHandle, "disable_close", rb_fiddle_handle_disable_close, 0);
|
473
531
|
rb_define_method(rb_cHandle, "enable_close", rb_fiddle_handle_enable_close, 0);
|
474
532
|
rb_define_method(rb_cHandle, "close_enabled?", rb_fiddle_handle_close_enabled_p, 0);
|
data/ext/fiddle/memory_view.c
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
-
#include <
|
2
|
-
#include <ruby/ruby.h>
|
1
|
+
#include <fiddle.h>
|
3
2
|
|
4
3
|
#ifdef HAVE_RUBY_MEMORY_VIEW_H
|
5
|
-
|
6
|
-
#
|
4
|
+
|
5
|
+
#include <stdbool.h>
|
6
|
+
#include <ruby/ruby.h>
|
7
|
+
#include <ruby/encoding.h>
|
8
|
+
#include <ruby/memory_view.h>
|
7
9
|
|
8
10
|
#if SIZEOF_INTPTR_T == SIZEOF_LONG_LONG
|
9
11
|
# define INTPTR2NUM LL2NUM
|
@@ -16,9 +18,6 @@
|
|
16
18
|
# define UINTPTR2NUM UINT2NUM
|
17
19
|
#endif
|
18
20
|
|
19
|
-
#include <fiddle.h>
|
20
|
-
|
21
|
-
#ifdef FIDDLE_MEMORY_VIEW
|
22
21
|
VALUE rb_cMemoryView = Qnil;
|
23
22
|
|
24
23
|
struct memview_data {
|
@@ -35,12 +34,25 @@ fiddle_memview_mark(void *ptr)
|
|
35
34
|
}
|
36
35
|
|
37
36
|
static void
|
38
|
-
|
37
|
+
fiddle_memview_release(struct memview_data *data)
|
39
38
|
{
|
40
|
-
|
39
|
+
if (NIL_P(data->view.obj)) return;
|
40
|
+
|
41
41
|
rb_memory_view_release(&data->view);
|
42
|
-
|
42
|
+
data->view.obj = Qnil;
|
43
|
+
data->view.byte_size = 0;
|
44
|
+
if (data->members) {
|
43
45
|
xfree(data->members);
|
46
|
+
data->members = NULL;
|
47
|
+
data->n_members = 0;
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
static void
|
52
|
+
fiddle_memview_free(void *ptr)
|
53
|
+
{
|
54
|
+
struct memview_data *data = ptr;
|
55
|
+
fiddle_memview_release(data);
|
44
56
|
xfree(ptr);
|
45
57
|
}
|
46
58
|
|
@@ -62,11 +74,32 @@ rb_fiddle_memview_s_allocate(VALUE klass)
|
|
62
74
|
struct memview_data *data;
|
63
75
|
VALUE obj = TypedData_Make_Struct(klass, struct memview_data, &fiddle_memview_data_type, data);
|
64
76
|
data->view.obj = Qnil;
|
77
|
+
data->view.byte_size = 0;
|
65
78
|
data->members = NULL;
|
66
79
|
data->n_members = 0;
|
67
80
|
return obj;
|
68
81
|
}
|
69
82
|
|
83
|
+
static VALUE
|
84
|
+
rb_fiddle_memview_release(VALUE obj)
|
85
|
+
{
|
86
|
+
struct memview_data *data;
|
87
|
+
TypedData_Get_Struct(obj, struct memview_data, &fiddle_memview_data_type, data);
|
88
|
+
|
89
|
+
if (NIL_P(data->view.obj)) return Qnil;
|
90
|
+
fiddle_memview_release(data);
|
91
|
+
return Qnil;
|
92
|
+
}
|
93
|
+
|
94
|
+
static VALUE
|
95
|
+
rb_fiddle_memview_s_export(VALUE klass, VALUE target)
|
96
|
+
{
|
97
|
+
ID id_new;
|
98
|
+
CONST_ID(id_new, "new");
|
99
|
+
VALUE memview = rb_funcall(klass, id_new, 1, target);
|
100
|
+
return rb_ensure(rb_yield, memview, rb_fiddle_memview_release, memview);
|
101
|
+
}
|
102
|
+
|
70
103
|
static VALUE
|
71
104
|
rb_fiddle_memview_initialize(VALUE obj, VALUE target)
|
72
105
|
{
|
@@ -74,6 +107,7 @@ rb_fiddle_memview_initialize(VALUE obj, VALUE target)
|
|
74
107
|
TypedData_Get_Struct(obj, struct memview_data, &fiddle_memview_data_type, data);
|
75
108
|
|
76
109
|
if (!rb_memory_view_get(target, &data->view, 0)) {
|
110
|
+
data->view.obj = Qnil;
|
77
111
|
rb_raise(rb_eArgError, "Unable to get a memory view from %+"PRIsVALUE, target);
|
78
112
|
}
|
79
113
|
|
@@ -233,12 +267,44 @@ rb_fiddle_memview_aref(int argc, VALUE *argv, VALUE obj)
|
|
233
267
|
return rb_memory_view_extract_item_members(ptr, data->members, data->n_members);
|
234
268
|
}
|
235
269
|
|
270
|
+
static VALUE
|
271
|
+
rb_fiddle_memview_to_s(VALUE self)
|
272
|
+
{
|
273
|
+
struct memview_data *data;
|
274
|
+
const char *raw_data;
|
275
|
+
long byte_size;
|
276
|
+
VALUE string;
|
277
|
+
|
278
|
+
TypedData_Get_Struct(self,
|
279
|
+
struct memview_data,
|
280
|
+
&fiddle_memview_data_type,
|
281
|
+
data);
|
282
|
+
|
283
|
+
if (NIL_P(data->view.obj)) {
|
284
|
+
raw_data = NULL;
|
285
|
+
byte_size = 0;
|
286
|
+
} else {
|
287
|
+
raw_data = data->view.data;
|
288
|
+
byte_size = data->view.byte_size;
|
289
|
+
}
|
290
|
+
|
291
|
+
string = rb_enc_str_new_static(raw_data, byte_size, rb_ascii8bit_encoding());
|
292
|
+
{
|
293
|
+
ID id_memory_view;
|
294
|
+
CONST_ID(id_memory_view, "memory_view");
|
295
|
+
rb_ivar_set(string, id_memory_view, self);
|
296
|
+
}
|
297
|
+
return rb_obj_freeze(string);
|
298
|
+
}
|
299
|
+
|
236
300
|
void
|
237
301
|
Init_fiddle_memory_view(void)
|
238
302
|
{
|
239
303
|
rb_cMemoryView = rb_define_class_under(mFiddle, "MemoryView", rb_cObject);
|
240
304
|
rb_define_alloc_func(rb_cMemoryView, rb_fiddle_memview_s_allocate);
|
305
|
+
rb_define_singleton_method(rb_cMemoryView, "export", rb_fiddle_memview_s_export, 1);
|
241
306
|
rb_define_method(rb_cMemoryView, "initialize", rb_fiddle_memview_initialize, 1);
|
307
|
+
rb_define_method(rb_cMemoryView, "release", rb_fiddle_memview_release, 0);
|
242
308
|
rb_define_method(rb_cMemoryView, "obj", rb_fiddle_memview_get_obj, 0);
|
243
309
|
rb_define_method(rb_cMemoryView, "byte_size", rb_fiddle_memview_get_byte_size, 0);
|
244
310
|
rb_define_method(rb_cMemoryView, "readonly?", rb_fiddle_memview_get_readonly, 0);
|
@@ -249,6 +315,7 @@ Init_fiddle_memory_view(void)
|
|
249
315
|
rb_define_method(rb_cMemoryView, "strides", rb_fiddle_memview_get_strides, 0);
|
250
316
|
rb_define_method(rb_cMemoryView, "sub_offsets", rb_fiddle_memview_get_sub_offsets, 0);
|
251
317
|
rb_define_method(rb_cMemoryView, "[]", rb_fiddle_memview_aref, -1);
|
318
|
+
rb_define_method(rb_cMemoryView, "to_s", rb_fiddle_memview_to_s, 0);
|
252
319
|
}
|
253
320
|
|
254
|
-
#endif /*
|
321
|
+
#endif /* HAVE_RUBY_MEMORY_VIEW_H */
|
data/ext/fiddle/pointer.c
CHANGED
@@ -6,13 +6,13 @@
|
|
6
6
|
#include <ruby/ruby.h>
|
7
7
|
#include <ruby/io.h>
|
8
8
|
|
9
|
+
#include <ctype.h>
|
10
|
+
#include <fiddle.h>
|
11
|
+
|
9
12
|
#ifdef HAVE_RUBY_MEMORY_VIEW_H
|
10
13
|
# include <ruby/memory_view.h>
|
11
14
|
#endif
|
12
15
|
|
13
|
-
#include <ctype.h>
|
14
|
-
#include <fiddle.h>
|
15
|
-
|
16
16
|
#ifdef PRIsVALUE
|
17
17
|
# define RB_OBJ_CLASSNAME(obj) rb_obj_class(obj)
|
18
18
|
# define RB_OBJ_STRING(obj) (obj)
|
@@ -24,7 +24,7 @@
|
|
24
24
|
|
25
25
|
VALUE rb_cPointer;
|
26
26
|
|
27
|
-
typedef
|
27
|
+
typedef rb_fiddle_freefunc_t freefunc_t;
|
28
28
|
|
29
29
|
struct ptr_data {
|
30
30
|
void *ptr;
|
@@ -92,7 +92,7 @@ static const rb_data_type_t fiddle_ptr_data_type = {
|
|
92
92
|
{fiddle_ptr_mark, fiddle_ptr_free, fiddle_ptr_memsize,},
|
93
93
|
};
|
94
94
|
|
95
|
-
#ifdef
|
95
|
+
#ifdef HAVE_RUBY_MEMORY_VIEW_H
|
96
96
|
static struct ptr_data *
|
97
97
|
fiddle_ptr_check_memory_view(VALUE obj)
|
98
98
|
{
|
@@ -125,7 +125,7 @@ static const rb_memory_view_entry_t fiddle_ptr_memory_view_entry = {
|
|
125
125
|
#endif
|
126
126
|
|
127
127
|
static VALUE
|
128
|
-
rb_fiddle_ptr_new2(VALUE klass, void *ptr, long size, freefunc_t func)
|
128
|
+
rb_fiddle_ptr_new2(VALUE klass, void *ptr, long size, freefunc_t func, VALUE wrap0, VALUE wrap1)
|
129
129
|
{
|
130
130
|
struct ptr_data *data;
|
131
131
|
VALUE val;
|
@@ -135,14 +135,22 @@ rb_fiddle_ptr_new2(VALUE klass, void *ptr, long size, freefunc_t func)
|
|
135
135
|
data->free = func;
|
136
136
|
data->freed = false;
|
137
137
|
data->size = size;
|
138
|
+
data->wrap[0] = wrap0;
|
139
|
+
data->wrap[1] = wrap1;
|
138
140
|
|
139
141
|
return val;
|
140
142
|
}
|
141
143
|
|
144
|
+
VALUE
|
145
|
+
rb_fiddle_ptr_new_wrap(void *ptr, long size, freefunc_t func, VALUE wrap0, VALUE wrap1)
|
146
|
+
{
|
147
|
+
return rb_fiddle_ptr_new2(rb_cPointer, ptr, size, func, wrap0, wrap1);
|
148
|
+
}
|
149
|
+
|
142
150
|
static VALUE
|
143
151
|
rb_fiddle_ptr_new(void *ptr, long size, freefunc_t func)
|
144
152
|
{
|
145
|
-
return rb_fiddle_ptr_new2(rb_cPointer, ptr, size, func);
|
153
|
+
return rb_fiddle_ptr_new2(rb_cPointer, ptr, size, func, 0, 0);
|
146
154
|
}
|
147
155
|
|
148
156
|
static VALUE
|
@@ -152,7 +160,7 @@ rb_fiddle_ptr_malloc(VALUE klass, long size, freefunc_t func)
|
|
152
160
|
|
153
161
|
ptr = ruby_xmalloc((size_t)size);
|
154
162
|
memset(ptr,0,(size_t)size);
|
155
|
-
return rb_fiddle_ptr_new2(klass, ptr, size, func);
|
163
|
+
return rb_fiddle_ptr_new2(klass, ptr, size, func, 0, 0);
|
156
164
|
}
|
157
165
|
|
158
166
|
static void *
|
@@ -770,6 +778,7 @@ rb_fiddle_ptr_s_to_ptr(VALUE self, VALUE val)
|
|
770
778
|
}
|
771
779
|
else if (RTEST(rb_obj_is_kind_of(val, rb_cString))){
|
772
780
|
char *str = StringValuePtr(val);
|
781
|
+
wrap = val;
|
773
782
|
ptr = rb_fiddle_ptr_new(str, RSTRING_LEN(val), NULL);
|
774
783
|
}
|
775
784
|
else if ((vptr = rb_check_funcall(val, id_to_ptr, 0, 0)) != Qundef){
|
@@ -832,7 +841,7 @@ Init_fiddle_pointer(void)
|
|
832
841
|
rb_define_method(rb_cPointer, "size", rb_fiddle_ptr_size_get, 0);
|
833
842
|
rb_define_method(rb_cPointer, "size=", rb_fiddle_ptr_size_set, 1);
|
834
843
|
|
835
|
-
#ifdef
|
844
|
+
#ifdef HAVE_RUBY_MEMORY_VIEW_H
|
836
845
|
rb_memory_view_register(rb_cPointer, &fiddle_ptr_memory_view_entry);
|
837
846
|
#endif
|
838
847
|
|
data/fiddle.gemspec
CHANGED
@@ -56,11 +56,7 @@ Gem::Specification.new do |spec|
|
|
56
56
|
spec.require_paths = ["lib"]
|
57
57
|
spec.extensions = ["ext/fiddle/extconf.rb"]
|
58
58
|
|
59
|
-
spec.required_ruby_version = ">= 2.
|
60
|
-
|
61
|
-
spec.add_development_dependency "bundler"
|
62
|
-
spec.add_development_dependency "rake"
|
63
|
-
spec.add_development_dependency "rake-compiler"
|
59
|
+
spec.required_ruby_version = ">= 2.5.0"
|
64
60
|
|
65
61
|
spec.metadata["msys2_mingw_dependencies"] = "libffi"
|
66
62
|
end
|
data/lib/fiddle/cparser.rb
CHANGED
@@ -148,9 +148,11 @@ module Fiddle
|
|
148
148
|
#
|
149
149
|
def parse_ctype(ty, tymap=nil)
|
150
150
|
tymap ||= {}
|
151
|
-
|
152
|
-
when Array
|
151
|
+
if ty.is_a?(Array)
|
153
152
|
return [parse_ctype(ty[0], tymap), ty[1]]
|
153
|
+
end
|
154
|
+
ty = ty.gsub(/\Aconst\s+/, "")
|
155
|
+
case ty
|
154
156
|
when 'void'
|
155
157
|
return TYPE_VOID
|
156
158
|
when /\A(?:(?:signed\s+)?long\s+long(?:\s+int\s+)?|int64_t)(?:\s+\w+)?\z/
|
data/lib/fiddle/function.rb
CHANGED
data/lib/fiddle/struct.rb
CHANGED
@@ -13,6 +13,58 @@ module Fiddle
|
|
13
13
|
CStructEntity
|
14
14
|
end
|
15
15
|
|
16
|
+
def self.offsetof(name, members, types) # :nodoc:
|
17
|
+
offset = 0
|
18
|
+
worklist = name.split('.')
|
19
|
+
this_type = self
|
20
|
+
while search_name = worklist.shift
|
21
|
+
index = 0
|
22
|
+
member_index = members.index(search_name)
|
23
|
+
|
24
|
+
unless member_index
|
25
|
+
# Possibly a sub-structure
|
26
|
+
member_index = members.index { |member_name, _|
|
27
|
+
member_name == search_name
|
28
|
+
}
|
29
|
+
return unless member_index
|
30
|
+
end
|
31
|
+
|
32
|
+
types.each { |type, count = 1|
|
33
|
+
orig_offset = offset
|
34
|
+
if type.respond_to?(:entity_class)
|
35
|
+
align = type.alignment
|
36
|
+
type_size = type.size
|
37
|
+
else
|
38
|
+
align = PackInfo::ALIGN_MAP[type]
|
39
|
+
type_size = PackInfo::SIZE_MAP[type]
|
40
|
+
end
|
41
|
+
|
42
|
+
# Unions shouldn't advance the offset
|
43
|
+
if this_type.entity_class == CUnionEntity
|
44
|
+
type_size = 0
|
45
|
+
end
|
46
|
+
|
47
|
+
offset = PackInfo.align(orig_offset, align)
|
48
|
+
|
49
|
+
if worklist.empty?
|
50
|
+
return offset if index == member_index
|
51
|
+
else
|
52
|
+
if index == member_index
|
53
|
+
subtype = types[member_index]
|
54
|
+
members = subtype.members
|
55
|
+
types = subtype.types
|
56
|
+
this_type = subtype
|
57
|
+
break
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
offset += (type_size * count)
|
62
|
+
index += 1
|
63
|
+
}
|
64
|
+
end
|
65
|
+
nil
|
66
|
+
end
|
67
|
+
|
16
68
|
def each
|
17
69
|
return enum_for(__function__) unless block_given?
|
18
70
|
|
@@ -75,6 +127,10 @@ module Fiddle
|
|
75
127
|
def CUnion.entity_class
|
76
128
|
CUnionEntity
|
77
129
|
end
|
130
|
+
|
131
|
+
def self.offsetof(name, members, types) # :nodoc:
|
132
|
+
0
|
133
|
+
end
|
78
134
|
end
|
79
135
|
|
80
136
|
# Wrapper for arrays within a struct
|
@@ -172,6 +228,21 @@ module Fiddle
|
|
172
228
|
define_method(:to_i){ @entity.to_i }
|
173
229
|
define_singleton_method(:types) { types }
|
174
230
|
define_singleton_method(:members) { members }
|
231
|
+
|
232
|
+
# Return the offset of a struct member given its name.
|
233
|
+
# For example:
|
234
|
+
#
|
235
|
+
# MyStruct = struct [
|
236
|
+
# "int64_t i",
|
237
|
+
# "char c",
|
238
|
+
# ]
|
239
|
+
#
|
240
|
+
# MyStruct.offsetof("i") # => 0
|
241
|
+
# MyStruct.offsetof("c") # => 8
|
242
|
+
#
|
243
|
+
define_singleton_method(:offsetof) { |name|
|
244
|
+
klass.offsetof(name, members, types)
|
245
|
+
}
|
175
246
|
members.each{|name|
|
176
247
|
name = name[0] if name.is_a?(Array) # name is a nested struct
|
177
248
|
next if method_defined?(name)
|
data/lib/fiddle/types.rb
CHANGED
@@ -27,28 +27,29 @@ module Fiddle
|
|
27
27
|
# * WORD
|
28
28
|
module Win32Types
|
29
29
|
def included(m) # :nodoc:
|
30
|
+
# https://docs.microsoft.com/en-us/windows/win32/winprog/windows-data-types
|
30
31
|
m.module_eval{
|
31
|
-
typealias "
|
32
|
-
typealias "PDWORD", "unsigned long *"
|
33
|
-
typealias "DWORD32", "unsigned long"
|
34
|
-
typealias "DWORD64", "unsigned long long"
|
35
|
-
typealias "WORD", "unsigned short"
|
36
|
-
typealias "PWORD", "unsigned short *"
|
32
|
+
typealias "ATOM", "WORD"
|
37
33
|
typealias "BOOL", "int"
|
38
|
-
typealias "ATOM", "int"
|
39
34
|
typealias "BYTE", "unsigned char"
|
40
|
-
typealias "
|
35
|
+
typealias "DWORD", "unsigned long"
|
36
|
+
typealias "DWORD32", "uint32_t"
|
37
|
+
typealias "DWORD64", "uint64_t"
|
38
|
+
typealias "HANDLE", "PVOID"
|
39
|
+
typealias "HDC", "HANDLE"
|
40
|
+
typealias "HINSTANCE", "HANDLE"
|
41
|
+
typealias "HWND", "HANDLE"
|
42
|
+
typealias "LPCSTR", "const char *"
|
43
|
+
typealias "LPSTR", "char *"
|
44
|
+
typealias "PBYTE", "BYTE *"
|
45
|
+
typealias "PDWORD", "DWORD *"
|
46
|
+
typealias "PHANDLE", "HANDLE *"
|
47
|
+
typealias "PVOID", "void *"
|
48
|
+
typealias "PWORD", "WORD *"
|
49
|
+
typealias "UCHAR", "unsigned char"
|
41
50
|
typealias "UINT", "unsigned int"
|
42
51
|
typealias "ULONG", "unsigned long"
|
43
|
-
typealias "
|
44
|
-
typealias "HANDLE", "uintptr_t"
|
45
|
-
typealias "PHANDLE", "void*"
|
46
|
-
typealias "PVOID", "void*"
|
47
|
-
typealias "LPCSTR", "char*"
|
48
|
-
typealias "LPSTR", "char*"
|
49
|
-
typealias "HINSTANCE", "unsigned int"
|
50
|
-
typealias "HDC", "unsigned int"
|
51
|
-
typealias "HWND", "unsigned int"
|
52
|
+
typealias "WORD", "unsigned short"
|
52
53
|
}
|
53
54
|
end
|
54
55
|
module_function :included
|
data/lib/fiddle/version.rb
CHANGED
data/lib/fiddle.rb
CHANGED
@@ -17,6 +17,18 @@ module Fiddle
|
|
17
17
|
def self.win32_last_error= error
|
18
18
|
Thread.current[:__FIDDLE_WIN32_LAST_ERROR__] = error
|
19
19
|
end
|
20
|
+
|
21
|
+
# Returns the last win32 socket +Error+ of the current executing
|
22
|
+
# +Thread+ or nil if none
|
23
|
+
def self.win32_last_socket_error
|
24
|
+
Thread.current[:__FIDDLE_WIN32_LAST_SOCKET_ERROR__]
|
25
|
+
end
|
26
|
+
|
27
|
+
# Sets the last win32 socket +Error+ of the current executing
|
28
|
+
# +Thread+ to +error+
|
29
|
+
def self.win32_last_socket_error= error
|
30
|
+
Thread.current[:__FIDDLE_WIN32_LAST_SOCKET_ERROR__] = error
|
31
|
+
end
|
20
32
|
end
|
21
33
|
|
22
34
|
# Returns the last +Error+ of the current executing +Thread+ or nil if none
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fiddle
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aaron Patterson
|
@@ -9,50 +9,8 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
13
|
-
dependencies:
|
14
|
-
- !ruby/object:Gem::Dependency
|
15
|
-
name: bundler
|
16
|
-
requirement: !ruby/object:Gem::Requirement
|
17
|
-
requirements:
|
18
|
-
- - ">="
|
19
|
-
- !ruby/object:Gem::Version
|
20
|
-
version: '0'
|
21
|
-
type: :development
|
22
|
-
prerelease: false
|
23
|
-
version_requirements: !ruby/object:Gem::Requirement
|
24
|
-
requirements:
|
25
|
-
- - ">="
|
26
|
-
- !ruby/object:Gem::Version
|
27
|
-
version: '0'
|
28
|
-
- !ruby/object:Gem::Dependency
|
29
|
-
name: rake
|
30
|
-
requirement: !ruby/object:Gem::Requirement
|
31
|
-
requirements:
|
32
|
-
- - ">="
|
33
|
-
- !ruby/object:Gem::Version
|
34
|
-
version: '0'
|
35
|
-
type: :development
|
36
|
-
prerelease: false
|
37
|
-
version_requirements: !ruby/object:Gem::Requirement
|
38
|
-
requirements:
|
39
|
-
- - ">="
|
40
|
-
- !ruby/object:Gem::Version
|
41
|
-
version: '0'
|
42
|
-
- !ruby/object:Gem::Dependency
|
43
|
-
name: rake-compiler
|
44
|
-
requirement: !ruby/object:Gem::Requirement
|
45
|
-
requirements:
|
46
|
-
- - ">="
|
47
|
-
- !ruby/object:Gem::Version
|
48
|
-
version: '0'
|
49
|
-
type: :development
|
50
|
-
prerelease: false
|
51
|
-
version_requirements: !ruby/object:Gem::Requirement
|
52
|
-
requirements:
|
53
|
-
- - ">="
|
54
|
-
- !ruby/object:Gem::Version
|
55
|
-
version: '0'
|
12
|
+
date: 2021-10-22 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
56
14
|
description: A libffi wrapper for Ruby.
|
57
15
|
email:
|
58
16
|
- aaron@tenderlovemaking.com
|
@@ -111,14 +69,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
111
69
|
requirements:
|
112
70
|
- - ">="
|
113
71
|
- !ruby/object:Gem::Version
|
114
|
-
version: 2.
|
72
|
+
version: 2.5.0
|
115
73
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
116
74
|
requirements:
|
117
75
|
- - ">="
|
118
76
|
- !ruby/object:Gem::Version
|
119
77
|
version: '0'
|
120
78
|
requirements: []
|
121
|
-
rubygems_version: 3.
|
79
|
+
rubygems_version: 3.3.0.dev
|
122
80
|
signing_key:
|
123
81
|
specification_version: 4
|
124
82
|
summary: A libffi wrapper for Ruby.
|