fiddle 1.0.6 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
-
[](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.
|