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