00001
00002
00003
00004
00005 #include <ruby.h>
00006 #include "dl.h"
00007
00008 #define SafeStringValuePtr(v) (rb_string_value(&v), rb_check_safe_obj(v), RSTRING_PTR(v))
00009
00010 VALUE rb_cDLHandle;
00011
00012 #ifdef _WIN32
00013 # ifndef _WIN32_WCE
00014 static void *
00015 w32_coredll(void)
00016 {
00017 MEMORY_BASIC_INFORMATION m;
00018 memset(&m, 0, sizeof(m));
00019 if( !VirtualQuery(_errno, &m, sizeof(m)) ) return NULL;
00020 return m.AllocationBase;
00021 }
00022 # endif
00023
00024 static int
00025 w32_dlclose(void *ptr)
00026 {
00027 # ifndef _WIN32_WCE
00028 if( ptr == w32_coredll() ) return 0;
00029 # endif
00030 if( FreeLibrary((HMODULE)ptr) ) return 0;
00031 return errno = rb_w32_map_errno(GetLastError());
00032 }
00033 #define dlclose(ptr) w32_dlclose(ptr)
00034 #endif
00035
00036 static void
00037 dlhandle_free(void *ptr)
00038 {
00039 struct dl_handle *dlhandle = ptr;
00040 if( dlhandle->ptr && dlhandle->open && dlhandle->enable_close ){
00041 dlclose(dlhandle->ptr);
00042 }
00043 xfree(ptr);
00044 }
00045
00046 static size_t
00047 dlhandle_memsize(const void *ptr)
00048 {
00049 return ptr ? sizeof(struct dl_handle) : 0;
00050 }
00051
00052 static const rb_data_type_t dlhandle_data_type = {
00053 "dl/handle",
00054 {0, dlhandle_free, dlhandle_memsize,},
00055 };
00056
00057
00058
00059
00060
00061
00062
00063 VALUE
00064 rb_dlhandle_close(VALUE self)
00065 {
00066 struct dl_handle *dlhandle;
00067
00068 TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
00069 if(dlhandle->open) {
00070 int ret = dlclose(dlhandle->ptr);
00071 dlhandle->open = 0;
00072
00073
00074 if(ret) {
00075 #if defined(HAVE_DLERROR)
00076 rb_raise(rb_eDLError, "%s", dlerror());
00077 #else
00078 rb_raise(rb_eDLError, "could not close handle");
00079 #endif
00080 }
00081 return INT2NUM(ret);
00082 }
00083 rb_raise(rb_eDLError, "dlclose() called too many times");
00084
00085 UNREACHABLE;
00086 }
00087
00088 VALUE
00089 rb_dlhandle_s_allocate(VALUE klass)
00090 {
00091 VALUE obj;
00092 struct dl_handle *dlhandle;
00093
00094 obj = TypedData_Make_Struct(rb_cDLHandle, struct dl_handle, &dlhandle_data_type, dlhandle);
00095 dlhandle->ptr = 0;
00096 dlhandle->open = 0;
00097 dlhandle->enable_close = 0;
00098
00099 return obj;
00100 }
00101
00102 static VALUE
00103 predefined_dlhandle(void *handle)
00104 {
00105 VALUE obj = rb_dlhandle_s_allocate(rb_cDLHandle);
00106 struct dl_handle *dlhandle = DATA_PTR(obj);
00107
00108 dlhandle->ptr = handle;
00109 dlhandle->open = 1;
00110 OBJ_FREEZE(obj);
00111 return obj;
00112 }
00113
00114
00115
00116
00117
00118
00119
00120
00121 VALUE
00122 rb_dlhandle_initialize(int argc, VALUE argv[], VALUE self)
00123 {
00124 void *ptr;
00125 struct dl_handle *dlhandle;
00126 VALUE lib, flag;
00127 char *clib;
00128 int cflag;
00129 const char *err;
00130
00131 switch( rb_scan_args(argc, argv, "02", &lib, &flag) ){
00132 case 0:
00133 clib = NULL;
00134 cflag = RTLD_LAZY | RTLD_GLOBAL;
00135 break;
00136 case 1:
00137 clib = NIL_P(lib) ? NULL : SafeStringValuePtr(lib);
00138 cflag = RTLD_LAZY | RTLD_GLOBAL;
00139 break;
00140 case 2:
00141 clib = NIL_P(lib) ? NULL : SafeStringValuePtr(lib);
00142 cflag = NUM2INT(flag);
00143 break;
00144 default:
00145 rb_bug("rb_dlhandle_new");
00146 }
00147
00148 rb_secure(2);
00149
00150 #if defined(_WIN32)
00151 if( !clib ){
00152 HANDLE rb_libruby_handle(void);
00153 ptr = rb_libruby_handle();
00154 }
00155 else if( STRCASECMP(clib, "libc") == 0
00156 # ifdef RUBY_COREDLL
00157 || STRCASECMP(clib, RUBY_COREDLL) == 0
00158 || STRCASECMP(clib, RUBY_COREDLL".dll") == 0
00159 # endif
00160 ){
00161 # ifdef _WIN32_WCE
00162 ptr = dlopen("coredll.dll", cflag);
00163 # else
00164 ptr = w32_coredll();
00165 # endif
00166 }
00167 else
00168 #endif
00169 ptr = dlopen(clib, cflag);
00170 #if defined(HAVE_DLERROR)
00171 if( !ptr && (err = dlerror()) ){
00172 rb_raise(rb_eDLError, "%s", err);
00173 }
00174 #else
00175 if( !ptr ){
00176 err = dlerror();
00177 rb_raise(rb_eDLError, "%s", err);
00178 }
00179 #endif
00180 TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
00181 if( dlhandle->ptr && dlhandle->open && dlhandle->enable_close ){
00182 dlclose(dlhandle->ptr);
00183 }
00184 dlhandle->ptr = ptr;
00185 dlhandle->open = 1;
00186 dlhandle->enable_close = 0;
00187
00188 if( rb_block_given_p() ){
00189 rb_ensure(rb_yield, self, rb_dlhandle_close, self);
00190 }
00191
00192 return Qnil;
00193 }
00194
00195
00196
00197
00198
00199
00200 VALUE
00201 rb_dlhandle_enable_close(VALUE self)
00202 {
00203 struct dl_handle *dlhandle;
00204
00205 TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
00206 dlhandle->enable_close = 1;
00207 return Qnil;
00208 }
00209
00210
00211
00212
00213
00214
00215 VALUE
00216 rb_dlhandle_disable_close(VALUE self)
00217 {
00218 struct dl_handle *dlhandle;
00219
00220 TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
00221 dlhandle->enable_close = 0;
00222 return Qnil;
00223 }
00224
00225
00226
00227
00228
00229
00230
00231 static VALUE
00232 rb_dlhandle_close_enabled_p(VALUE self)
00233 {
00234 struct dl_handle *dlhandle;
00235
00236 TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
00237
00238 if(dlhandle->enable_close) return Qtrue;
00239 return Qfalse;
00240 }
00241
00242
00243
00244
00245
00246
00247 VALUE
00248 rb_dlhandle_to_i(VALUE self)
00249 {
00250 struct dl_handle *dlhandle;
00251
00252 TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
00253 return PTR2NUM(dlhandle);
00254 }
00255
00256 static VALUE dlhandle_sym(void *handle, const char *symbol);
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266 VALUE
00267 rb_dlhandle_sym(VALUE self, VALUE sym)
00268 {
00269 struct dl_handle *dlhandle;
00270 const char *name;
00271
00272 name = SafeStringValuePtr(sym);
00273
00274 TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
00275 if( ! dlhandle->open ){
00276 rb_raise(rb_eDLError, "closed handle");
00277 }
00278
00279 return dlhandle_sym(dlhandle->ptr, name);
00280 }
00281
00282 #ifndef RTLD_NEXT
00283 #define RTLD_NEXT NULL
00284 #endif
00285 #ifndef RTLD_DEFAULT
00286 #define RTLD_DEFAULT NULL
00287 #endif
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298 VALUE
00299 rb_dlhandle_s_sym(VALUE self, VALUE sym)
00300 {
00301 return dlhandle_sym(RTLD_NEXT, StringValueCStr(sym));
00302 }
00303
00304 static VALUE
00305 dlhandle_sym(void *handle, const char *name)
00306 {
00307 #if defined(HAVE_DLERROR)
00308 const char *err;
00309 # define CHECK_DLERROR if( err = dlerror() ){ func = 0; }
00310 #else
00311 # define CHECK_DLERROR
00312 #endif
00313 void (*func)();
00314
00315 rb_secure(2);
00316 #ifdef HAVE_DLERROR
00317 dlerror();
00318 #endif
00319 func = (void (*)())(VALUE)dlsym(handle, name);
00320 CHECK_DLERROR;
00321 #if defined(FUNC_STDCALL)
00322 if( !func ){
00323 int i;
00324 int len = (int)strlen(name);
00325 char *name_n;
00326 #if defined(__CYGWIN__) || defined(_WIN32) || defined(__MINGW32__)
00327 {
00328 char *name_a = (char*)xmalloc(len+2);
00329 strcpy(name_a, name);
00330 name_n = name_a;
00331 name_a[len] = 'A';
00332 name_a[len+1] = '\0';
00333 func = dlsym(handle, name_a);
00334 CHECK_DLERROR;
00335 if( func ) goto found;
00336 name_n = xrealloc(name_a, len+6);
00337 }
00338 #else
00339 name_n = (char*)xmalloc(len+6);
00340 #endif
00341 memcpy(name_n, name, len);
00342 name_n[len++] = '@';
00343 for( i = 0; i < 256; i += 4 ){
00344 sprintf(name_n + len, "%d", i);
00345 func = dlsym(handle, name_n);
00346 CHECK_DLERROR;
00347 if( func ) break;
00348 }
00349 if( func ) goto found;
00350 name_n[len-1] = 'A';
00351 name_n[len++] = '@';
00352 for( i = 0; i < 256; i += 4 ){
00353 sprintf(name_n + len, "%d", i);
00354 func = dlsym(handle, name_n);
00355 CHECK_DLERROR;
00356 if( func ) break;
00357 }
00358 found:
00359 xfree(name_n);
00360 }
00361 #endif
00362 if( !func ){
00363 rb_raise(rb_eDLError, "unknown symbol \"%s\"", name);
00364 }
00365
00366 return PTR2NUM(func);
00367 }
00368
00369 void
00370 Init_dlhandle(void)
00371 {
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404 rb_cDLHandle = rb_define_class_under(rb_mDL, "Handle", rb_cObject);
00405 rb_define_alloc_func(rb_cDLHandle, rb_dlhandle_s_allocate);
00406 rb_define_singleton_method(rb_cDLHandle, "sym", rb_dlhandle_s_sym, 1);
00407 rb_define_singleton_method(rb_cDLHandle, "[]", rb_dlhandle_s_sym, 1);
00408
00409
00410
00411
00412
00413
00414
00415
00416 rb_define_const(rb_cDLHandle, "NEXT", predefined_dlhandle(RTLD_NEXT));
00417
00418
00419
00420
00421
00422
00423
00424
00425 rb_define_const(rb_cDLHandle, "DEFAULT", predefined_dlhandle(RTLD_DEFAULT));
00426 rb_define_method(rb_cDLHandle, "initialize", rb_dlhandle_initialize, -1);
00427 rb_define_method(rb_cDLHandle, "to_i", rb_dlhandle_to_i, 0);
00428 rb_define_method(rb_cDLHandle, "close", rb_dlhandle_close, 0);
00429 rb_define_method(rb_cDLHandle, "sym", rb_dlhandle_sym, 1);
00430 rb_define_method(rb_cDLHandle, "[]", rb_dlhandle_sym, 1);
00431 rb_define_method(rb_cDLHandle, "disable_close", rb_dlhandle_disable_close, 0);
00432 rb_define_method(rb_cDLHandle, "enable_close", rb_dlhandle_enable_close, 0);
00433 rb_define_method(rb_cDLHandle, "close_enabled?", rb_dlhandle_close_enabled_p, 0);
00434 }
00435
00436
00437