00001
00002
00003
00004
00005 #include <ruby.h>
00006 #include "dl.h"
00007
00008 VALUE rb_cDLHandle;
00009
00010 #ifdef HAVE_WINDOWS_H
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(HAVE_WINDOWS_H)
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 func = (void (*)())(VALUE)dlsym(handle, name);
00309 CHECK_DLERROR;
00310 #if defined(FUNC_STDCALL)
00311 if( !func ){
00312 int i;
00313 int len = strlen(name);
00314 char *name_n;
00315 #if defined(__CYGWIN__) || defined(_WIN32) || defined(__MINGW32__)
00316 {
00317 char *name_a = (char*)xmalloc(len+2);
00318 strcpy(name_a, name);
00319 name_n = name_a;
00320 name_a[len] = 'A';
00321 name_a[len+1] = '\0';
00322 func = dlsym(handle, name_a);
00323 CHECK_DLERROR;
00324 if( func ) goto found;
00325 name_n = xrealloc(name_a, len+6);
00326 }
00327 #else
00328 name_n = (char*)xmalloc(len+6);
00329 #endif
00330 memcpy(name_n, name, len);
00331 name_n[len++] = '@';
00332 for( i = 0; i < 256; i += 4 ){
00333 sprintf(name_n + len, "%d", i);
00334 func = dlsym(handle, name_n);
00335 CHECK_DLERROR;
00336 if( func ) break;
00337 }
00338 if( func ) goto found;
00339 name_n[len-1] = 'A';
00340 name_n[len++] = '@';
00341 for( i = 0; i < 256; i += 4 ){
00342 sprintf(name_n + len, "%d", i);
00343 func = dlsym(handle, name_n);
00344 CHECK_DLERROR;
00345 if( func ) break;
00346 }
00347 found:
00348 xfree(name_n);
00349 }
00350 #endif
00351 if( !func ){
00352 rb_raise(rb_eDLError, "unknown symbol \"%s\"", name);
00353 }
00354
00355 return PTR2NUM(func);
00356 }
00357
00358 void
00359 Init_dlhandle(void)
00360 {
00361 rb_cDLHandle = rb_define_class_under(rb_mDL, "Handle", rb_cObject);
00362 rb_define_alloc_func(rb_cDLHandle, rb_dlhandle_s_allocate);
00363 rb_define_singleton_method(rb_cDLHandle, "sym", rb_dlhandle_s_sym, 1);
00364 rb_define_singleton_method(rb_cDLHandle, "[]", rb_dlhandle_s_sym, 1);
00365 rb_define_const(rb_cDLHandle, "NEXT", predefined_dlhandle(RTLD_NEXT));
00366 rb_define_const(rb_cDLHandle, "DEFAULT", predefined_dlhandle(RTLD_DEFAULT));
00367 rb_define_method(rb_cDLHandle, "initialize", rb_dlhandle_initialize, -1);
00368 rb_define_method(rb_cDLHandle, "to_i", rb_dlhandle_to_i, 0);
00369 rb_define_method(rb_cDLHandle, "close", rb_dlhandle_close, 0);
00370 rb_define_method(rb_cDLHandle, "sym", rb_dlhandle_sym, 1);
00371 rb_define_method(rb_cDLHandle, "[]", rb_dlhandle_sym, 1);
00372 rb_define_method(rb_cDLHandle, "disable_close", rb_dlhandle_disable_close, 0);
00373 rb_define_method(rb_cDLHandle, "enable_close", rb_dlhandle_enable_close, 0);
00374 rb_define_method(rb_cDLHandle, "close_enabled?", rb_dlhandle_close_enabled_p, 0);
00375 }
00376
00377
00378