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