Skip to content

Commit 9d3371d

Browse files
tenderlovekou
andauthored
Add sym_defined? methods to test if a symbol is defined (#108)
I would like to check if a symbol is defined before trying to access it. Some symbols aren't available on all platforms, so instead of raising an exception, I want to check if it's defined first. Today we have to do: ```ruby begin addr = Fiddle::Handle.sym("something") # do something rescue Fiddle::DLError end ``` I want to write this: ```ruby if Fiddle::Handle.sym_defined?("something") addr = Fiddle::Handle.sym("something") # do something end ``` Co-authored-by: Sutou Kouhei <kou@clear-code.com>
1 parent 49fa723 commit 9d3371d

File tree

2 files changed

+59
-4
lines changed

2 files changed

+59
-4
lines changed

ext/fiddle/handle.c

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -321,22 +321,24 @@ rb_fiddle_handle_s_sym(VALUE self, VALUE sym)
321321
return fiddle_handle_sym(RTLD_NEXT, sym);
322322
}
323323

324-
static VALUE
325-
fiddle_handle_sym(void *handle, VALUE symbol)
324+
typedef void (*fiddle_void_func)(void);
325+
326+
static fiddle_void_func
327+
fiddle_handle_find_func(void *handle, VALUE symbol)
326328
{
327329
#if defined(HAVE_DLERROR)
328330
const char *err;
329331
# define CHECK_DLERROR if ((err = dlerror()) != 0) { func = 0; }
330332
#else
331333
# define CHECK_DLERROR
332334
#endif
333-
void (*func)();
335+
fiddle_void_func func;
334336
const char *name = StringValueCStr(symbol);
335337

336338
#ifdef HAVE_DLERROR
337339
dlerror();
338340
#endif
339-
func = (void (*)())(VALUE)dlsym(handle, name);
341+
func = (fiddle_void_func)(VALUE)dlsym(handle, name);
340342
CHECK_DLERROR;
341343
#if defined(FUNC_STDCALL)
342344
if( !func ){
@@ -379,6 +381,53 @@ fiddle_handle_sym(void *handle, VALUE symbol)
379381
xfree(name_n);
380382
}
381383
#endif
384+
385+
return func;
386+
}
387+
388+
static VALUE
389+
rb_fiddle_handle_s_sym_defined(VALUE self, VALUE sym)
390+
{
391+
fiddle_void_func func;
392+
393+
func = fiddle_handle_find_func(RTLD_NEXT, sym);
394+
395+
if( func ) {
396+
return PTR2NUM(func);
397+
}
398+
else {
399+
return Qnil;
400+
}
401+
}
402+
403+
static VALUE
404+
rb_fiddle_handle_sym_defined(VALUE self, VALUE sym)
405+
{
406+
struct dl_handle *fiddle_handle;
407+
fiddle_void_func func;
408+
409+
TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
410+
if( ! fiddle_handle->open ){
411+
rb_raise(rb_eFiddleDLError, "closed handle");
412+
}
413+
414+
func = fiddle_handle_find_func(fiddle_handle->ptr, sym);
415+
416+
if( func ) {
417+
return PTR2NUM(func);
418+
}
419+
else {
420+
return Qnil;
421+
}
422+
}
423+
424+
static VALUE
425+
fiddle_handle_sym(void *handle, VALUE symbol)
426+
{
427+
fiddle_void_func func;
428+
429+
func = fiddle_handle_find_func(handle, symbol);
430+
382431
if( !func ){
383432
rb_raise(rb_eFiddleDLError, "unknown symbol \"%"PRIsVALUE"\"", symbol);
384433
}
@@ -468,6 +517,7 @@ Init_fiddle_handle(void)
468517
rb_cHandle = rb_define_class_under(mFiddle, "Handle", rb_cObject);
469518
rb_define_alloc_func(rb_cHandle, rb_fiddle_handle_s_allocate);
470519
rb_define_singleton_method(rb_cHandle, "sym", rb_fiddle_handle_s_sym, 1);
520+
rb_define_singleton_method(rb_cHandle, "sym_defined?", rb_fiddle_handle_s_sym_defined, 1);
471521
rb_define_singleton_method(rb_cHandle, "[]", rb_fiddle_handle_s_sym, 1);
472522

473523
/* Document-const: NEXT
@@ -526,6 +576,7 @@ Init_fiddle_handle(void)
526576
rb_define_method(rb_cHandle, "close", rb_fiddle_handle_close, 0);
527577
rb_define_method(rb_cHandle, "sym", rb_fiddle_handle_sym, 1);
528578
rb_define_method(rb_cHandle, "[]", rb_fiddle_handle_sym, 1);
579+
rb_define_method(rb_cHandle, "sym_defined?", rb_fiddle_handle_sym_defined, 1);
529580
rb_define_method(rb_cHandle, "file_name", rb_fiddle_handle_file_name, 0);
530581
rb_define_method(rb_cHandle, "disable_close", rb_fiddle_handle_disable_close, 0);
531582
rb_define_method(rb_cHandle, "enable_close", rb_fiddle_handle_enable_close, 0);

test/fiddle/test_handle.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,14 @@ def test_to_ptr
2222
def test_static_sym_unknown
2323
assert_raise(DLError) { Fiddle::Handle.sym('fooo') }
2424
assert_raise(DLError) { Fiddle::Handle['fooo'] }
25+
refute Fiddle::Handle.sym_defined?('fooo')
2526
end
2627

2728
def test_static_sym
2829
begin
2930
# Linux / Darwin / FreeBSD
3031
refute_nil Fiddle::Handle.sym('dlopen')
32+
assert Fiddle::Handle.sym_defined?('dlopen')
3133
assert_equal Fiddle::Handle.sym('dlopen'), Fiddle::Handle['dlopen']
3234
return
3335
rescue
@@ -54,6 +56,7 @@ def test_sym_unknown
5456
handle = Fiddle::Handle.new(LIBC_SO)
5557
assert_raise(DLError) { handle.sym('fooo') }
5658
assert_raise(DLError) { handle['fooo'] }
59+
refute handle.sym_defined?('fooo')
5760
end
5861

5962
def test_sym_with_bad_args
@@ -66,6 +69,7 @@ def test_sym
6669
handle = Handle.new(LIBC_SO)
6770
refute_nil handle.sym('calloc')
6871
refute_nil handle['calloc']
72+
assert handle.sym_defined?('calloc')
6973
end
7074

7175
def test_handle_close

0 commit comments

Comments
 (0)