00001
00002
00003
00004
00005 #include <ruby/ruby.h>
00006 #include <ruby/io.h>
00007 #include <ctype.h>
00008 #include "dl.h"
00009
00010 #ifdef PRIsVALUE
00011 # define RB_OBJ_CLASSNAME(obj) rb_obj_class(obj)
00012 # define RB_OBJ_STRING(obj) (obj)
00013 #else
00014 # define PRIsVALUE "s"
00015 # define RB_OBJ_CLASSNAME(obj) rb_obj_classname(obj)
00016 # define RB_OBJ_STRING(obj) StringValueCStr(obj)
00017 #endif
00018
00019 VALUE rb_cDLCPtr;
00020
00021 static inline freefunc_t
00022 get_freefunc(VALUE func, volatile VALUE *wrap)
00023 {
00024 VALUE addrnum;
00025 if (NIL_P(func)) {
00026 *wrap = 0;
00027 return NULL;
00028 }
00029 if (rb_dlcfunc_kind_p(func)) {
00030 *wrap = func;
00031 return (freefunc_t)(VALUE)RCFUNC_DATA(func)->ptr;
00032 }
00033 addrnum = rb_Integer(func);
00034 *wrap = (addrnum != func) ? func : 0;
00035 return (freefunc_t)(VALUE)NUM2PTR(addrnum);
00036 }
00037
00038 static ID id_to_ptr;
00039
00040 static void
00041 dlptr_mark(void *ptr)
00042 {
00043 struct ptr_data *data = ptr;
00044 if (data->wrap[0]) {
00045 rb_gc_mark(data->wrap[0]);
00046 }
00047 if (data->wrap[1]) {
00048 rb_gc_mark(data->wrap[1]);
00049 }
00050 }
00051
00052 static void
00053 dlptr_free(void *ptr)
00054 {
00055 struct ptr_data *data = ptr;
00056 if (data->ptr) {
00057 if (data->free) {
00058 (*(data->free))(data->ptr);
00059 }
00060 }
00061 }
00062
00063 static size_t
00064 dlptr_memsize(const void *ptr)
00065 {
00066 const struct ptr_data *data = ptr;
00067 return data ? sizeof(*data) + data->size : 0;
00068 }
00069
00070 static const rb_data_type_t dlptr_data_type = {
00071 "dl/ptr",
00072 {dlptr_mark, dlptr_free, dlptr_memsize,},
00073 };
00074
00075 void
00076 dlptr_init(VALUE val)
00077 {
00078 struct ptr_data *data;
00079
00080 TypedData_Get_Struct(val, struct ptr_data, &dlptr_data_type, data);
00081 OBJ_TAINT(val);
00082 }
00083
00084 VALUE
00085 rb_dlptr_new2(VALUE klass, void *ptr, long size, freefunc_t func)
00086 {
00087 struct ptr_data *data;
00088 VALUE val;
00089
00090 rb_secure(4);
00091 val = TypedData_Make_Struct(klass, struct ptr_data, &dlptr_data_type, data);
00092 data->ptr = ptr;
00093 data->free = func;
00094 data->size = size;
00095 dlptr_init(val);
00096
00097 return val;
00098 }
00099
00100 VALUE
00101 rb_dlptr_new(void *ptr, long size, freefunc_t func)
00102 {
00103 return rb_dlptr_new2(rb_cDLCPtr, ptr, size, func);
00104 }
00105
00106 VALUE
00107 rb_dlptr_malloc(long size, freefunc_t func)
00108 {
00109 void *ptr;
00110
00111 rb_secure(4);
00112 ptr = ruby_xmalloc((size_t)size);
00113 memset(ptr,0,(size_t)size);
00114 return rb_dlptr_new(ptr, size, func);
00115 }
00116
00117 void *
00118 rb_dlptr2cptr(VALUE val)
00119 {
00120 struct ptr_data *data;
00121 void *ptr;
00122
00123 if (rb_obj_is_kind_of(val, rb_cDLCPtr)) {
00124 TypedData_Get_Struct(val, struct ptr_data, &dlptr_data_type, data);
00125 ptr = data->ptr;
00126 }
00127 else if (val == Qnil) {
00128 ptr = NULL;
00129 }
00130 else{
00131 rb_raise(rb_eTypeError, "DL::PtrData was expected");
00132 }
00133
00134 return ptr;
00135 }
00136
00137 static VALUE
00138 rb_dlptr_s_allocate(VALUE klass)
00139 {
00140 VALUE obj;
00141 struct ptr_data *data;
00142
00143 rb_secure(4);
00144 obj = TypedData_Make_Struct(klass, struct ptr_data, &dlptr_data_type, data);
00145 data->ptr = 0;
00146 data->size = 0;
00147 data->free = 0;
00148
00149 return obj;
00150 }
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161 static VALUE
00162 rb_dlptr_initialize(int argc, VALUE argv[], VALUE self)
00163 {
00164 VALUE ptr, sym, size, wrap = 0, funcwrap = 0;
00165 struct ptr_data *data;
00166 void *p = NULL;
00167 freefunc_t f = NULL;
00168 long s = 0;
00169
00170 if (rb_scan_args(argc, argv, "12", &ptr, &size, &sym) >= 1) {
00171 VALUE addrnum = rb_Integer(ptr);
00172 if (addrnum != ptr) wrap = ptr;
00173 p = NUM2PTR(addrnum);
00174 }
00175 if (argc >= 2) {
00176 s = NUM2LONG(size);
00177 }
00178 if (argc >= 3) {
00179 f = get_freefunc(sym, &funcwrap);
00180 }
00181
00182 if (p) {
00183 TypedData_Get_Struct(self, struct ptr_data, &dlptr_data_type, data);
00184 if (data->ptr && data->free) {
00185
00186 (*(data->free))(data->ptr);
00187 }
00188 data->wrap[0] = wrap;
00189 data->wrap[1] = funcwrap;
00190 data->ptr = p;
00191 data->size = s;
00192 data->free = f;
00193 }
00194
00195 return Qnil;
00196 }
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208 static VALUE
00209 rb_dlptr_s_malloc(int argc, VALUE argv[], VALUE klass)
00210 {
00211 VALUE size, sym, obj, wrap = 0;
00212 long s;
00213 freefunc_t f;
00214
00215 switch (rb_scan_args(argc, argv, "11", &size, &sym)) {
00216 case 1:
00217 s = NUM2LONG(size);
00218 f = NULL;
00219 break;
00220 case 2:
00221 s = NUM2LONG(size);
00222 f = get_freefunc(sym, &wrap);
00223 break;
00224 default:
00225 rb_bug("rb_dlptr_s_malloc");
00226 }
00227
00228 obj = rb_dlptr_malloc(s,f);
00229 if (wrap) RPTR_DATA(obj)->wrap[1] = wrap;
00230
00231 return obj;
00232 }
00233
00234
00235
00236
00237
00238
00239 static VALUE
00240 rb_dlptr_to_i(VALUE self)
00241 {
00242 struct ptr_data *data;
00243
00244 TypedData_Get_Struct(self, struct ptr_data, &dlptr_data_type, data);
00245 return PTR2NUM(data->ptr);
00246 }
00247
00248
00249
00250
00251
00252
00253 static VALUE
00254 rb_dlptr_to_value(VALUE self)
00255 {
00256 struct ptr_data *data;
00257 TypedData_Get_Struct(self, struct ptr_data, &dlptr_data_type, data);
00258 return (VALUE)(data->ptr);
00259 }
00260
00261
00262
00263
00264
00265
00266
00267 VALUE
00268 rb_dlptr_ptr(VALUE self)
00269 {
00270 struct ptr_data *data;
00271
00272 TypedData_Get_Struct(self, struct ptr_data, &dlptr_data_type, data);
00273 return rb_dlptr_new(*((void**)(data->ptr)),0,0);
00274 }
00275
00276
00277
00278
00279
00280
00281
00282 VALUE
00283 rb_dlptr_ref(VALUE self)
00284 {
00285 struct ptr_data *data;
00286
00287 TypedData_Get_Struct(self, struct ptr_data, &dlptr_data_type, data);
00288 return rb_dlptr_new(&(data->ptr),0,0);
00289 }
00290
00291
00292
00293
00294
00295
00296 VALUE
00297 rb_dlptr_null_p(VALUE self)
00298 {
00299 struct ptr_data *data;
00300
00301 TypedData_Get_Struct(self, struct ptr_data, &dlptr_data_type, data);
00302 return data->ptr ? Qfalse : Qtrue;
00303 }
00304
00305
00306
00307
00308
00309
00310 static VALUE
00311 rb_dlptr_free_set(VALUE self, VALUE val)
00312 {
00313 struct ptr_data *data;
00314
00315 TypedData_Get_Struct(self, struct ptr_data, &dlptr_data_type, data);
00316 data->free = get_freefunc(val, &data->wrap[1]);
00317
00318 return Qnil;
00319 }
00320
00321
00322
00323
00324
00325
00326 static VALUE
00327 rb_dlptr_free_get(VALUE self)
00328 {
00329 struct ptr_data *pdata;
00330
00331 TypedData_Get_Struct(self, struct ptr_data, &dlptr_data_type, pdata);
00332
00333 return rb_dlcfunc_new(pdata->free, DLTYPE_VOID, "free<anonymous>", CFUNC_CDECL);
00334 }
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346 static VALUE
00347 rb_dlptr_to_s(int argc, VALUE argv[], VALUE self)
00348 {
00349 struct ptr_data *data;
00350 VALUE arg1, val;
00351 int len;
00352
00353 TypedData_Get_Struct(self, struct ptr_data, &dlptr_data_type, data);
00354 switch (rb_scan_args(argc, argv, "01", &arg1)) {
00355 case 0:
00356 val = rb_tainted_str_new2((char*)(data->ptr));
00357 break;
00358 case 1:
00359 len = NUM2INT(arg1);
00360 val = rb_tainted_str_new((char*)(data->ptr), len);
00361 break;
00362 default:
00363 rb_bug("rb_dlptr_to_s");
00364 }
00365
00366 return val;
00367 }
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379 static VALUE
00380 rb_dlptr_to_str(int argc, VALUE argv[], VALUE self)
00381 {
00382 struct ptr_data *data;
00383 VALUE arg1, val;
00384 int len;
00385
00386 TypedData_Get_Struct(self, struct ptr_data, &dlptr_data_type, data);
00387 switch (rb_scan_args(argc, argv, "01", &arg1)) {
00388 case 0:
00389 val = rb_tainted_str_new((char*)(data->ptr),data->size);
00390 break;
00391 case 1:
00392 len = NUM2INT(arg1);
00393 val = rb_tainted_str_new((char*)(data->ptr), len);
00394 break;
00395 default:
00396 rb_bug("rb_dlptr_to_str");
00397 }
00398
00399 return val;
00400 }
00401
00402
00403
00404
00405
00406
00407
00408 static VALUE
00409 rb_dlptr_inspect(VALUE self)
00410 {
00411 struct ptr_data *data;
00412
00413 TypedData_Get_Struct(self, struct ptr_data, &dlptr_data_type, data);
00414 return rb_sprintf("#<%"PRIsVALUE":%p ptr=%p size=%ld free=%p>",
00415 RB_OBJ_CLASSNAME(self), data, data->ptr, data->size, data->free);
00416 }
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426 VALUE
00427 rb_dlptr_eql(VALUE self, VALUE other)
00428 {
00429 void *ptr1, *ptr2;
00430
00431 if(!rb_obj_is_kind_of(other, rb_cDLCPtr)) return Qfalse;
00432
00433 ptr1 = rb_dlptr2cptr(self);
00434 ptr2 = rb_dlptr2cptr(other);
00435
00436 return ptr1 == ptr2 ? Qtrue : Qfalse;
00437 }
00438
00439
00440
00441
00442
00443
00444
00445
00446 static VALUE
00447 rb_dlptr_cmp(VALUE self, VALUE other)
00448 {
00449 void *ptr1, *ptr2;
00450 SIGNED_VALUE diff;
00451
00452 if(!rb_obj_is_kind_of(other, rb_cDLCPtr)) return Qnil;
00453
00454 ptr1 = rb_dlptr2cptr(self);
00455 ptr2 = rb_dlptr2cptr(other);
00456 diff = (SIGNED_VALUE)ptr1 - (SIGNED_VALUE)ptr2;
00457 if (!diff) return INT2FIX(0);
00458 return diff > 0 ? INT2NUM(1) : INT2NUM(-1);
00459 }
00460
00461
00462
00463
00464
00465
00466
00467 static VALUE
00468 rb_dlptr_plus(VALUE self, VALUE other)
00469 {
00470 void *ptr;
00471 long num, size;
00472
00473 ptr = rb_dlptr2cptr(self);
00474 size = RPTR_DATA(self)->size;
00475 num = NUM2LONG(other);
00476 return rb_dlptr_new((char *)ptr + num, size - num, 0);
00477 }
00478
00479
00480
00481
00482
00483
00484
00485 static VALUE
00486 rb_dlptr_minus(VALUE self, VALUE other)
00487 {
00488 void *ptr;
00489 long num, size;
00490
00491 ptr = rb_dlptr2cptr(self);
00492 size = RPTR_DATA(self)->size;
00493 num = NUM2LONG(other);
00494 return rb_dlptr_new((char *)ptr - num, size + num, 0);
00495 }
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506 VALUE
00507 rb_dlptr_aref(int argc, VALUE argv[], VALUE self)
00508 {
00509 VALUE arg0, arg1;
00510 VALUE retval = Qnil;
00511 size_t offset, len;
00512 struct ptr_data *data;
00513
00514 TypedData_Get_Struct(self, struct ptr_data, &dlptr_data_type, data);
00515 if (!data->ptr) rb_raise(rb_eDLError, "NULL pointer dereference");
00516 switch( rb_scan_args(argc, argv, "11", &arg0, &arg1) ){
00517 case 1:
00518 offset = NUM2ULONG(arg0);
00519 retval = INT2NUM(*((char *)data->ptr + offset));
00520 break;
00521 case 2:
00522 offset = NUM2ULONG(arg0);
00523 len = NUM2ULONG(arg1);
00524 retval = rb_tainted_str_new((char *)data->ptr + offset, len);
00525 break;
00526 default:
00527 rb_bug("rb_dlptr_aref()");
00528 }
00529 return retval;
00530 }
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541 VALUE
00542 rb_dlptr_aset(int argc, VALUE argv[], VALUE self)
00543 {
00544 VALUE arg0, arg1, arg2;
00545 VALUE retval = Qnil;
00546 size_t offset, len;
00547 void *mem;
00548 struct ptr_data *data;
00549
00550 TypedData_Get_Struct(self, struct ptr_data, &dlptr_data_type, data);
00551 if (!data->ptr) rb_raise(rb_eDLError, "NULL pointer dereference");
00552 switch( rb_scan_args(argc, argv, "21", &arg0, &arg1, &arg2) ){
00553 case 2:
00554 offset = NUM2ULONG(arg0);
00555 ((char*)data->ptr)[offset] = NUM2UINT(arg1);
00556 retval = arg1;
00557 break;
00558 case 3:
00559 offset = NUM2ULONG(arg0);
00560 len = NUM2ULONG(arg1);
00561 if (RB_TYPE_P(arg2, T_STRING)) {
00562 mem = StringValuePtr(arg2);
00563 }
00564 else if( rb_obj_is_kind_of(arg2, rb_cDLCPtr) ){
00565 mem = rb_dlptr2cptr(arg2);
00566 }
00567 else{
00568 mem = NUM2PTR(arg2);
00569 }
00570 memcpy((char *)data->ptr + offset, mem, len);
00571 retval = arg2;
00572 break;
00573 default:
00574 rb_bug("rb_dlptr_aset()");
00575 }
00576 return retval;
00577 }
00578
00579
00580
00581
00582
00583
00584 static VALUE
00585 rb_dlptr_size_set(VALUE self, VALUE size)
00586 {
00587 RPTR_DATA(self)->size = NUM2LONG(size);
00588 return size;
00589 }
00590
00591
00592
00593
00594
00595
00596 static VALUE
00597 rb_dlptr_size_get(VALUE self)
00598 {
00599 return LONG2NUM(RPTR_DATA(self)->size);
00600 }
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610 static VALUE
00611 rb_dlptr_s_to_ptr(VALUE self, VALUE val)
00612 {
00613 VALUE ptr, wrap = val, vptr;
00614
00615 if (RTEST(rb_obj_is_kind_of(val, rb_cIO))){
00616 rb_io_t *fptr;
00617 FILE *fp;
00618 GetOpenFile(val, fptr);
00619 fp = rb_io_stdio_file(fptr);
00620 ptr = rb_dlptr_new(fp, 0, NULL);
00621 }
00622 else if (RTEST(rb_obj_is_kind_of(val, rb_cString))){
00623 char *str = StringValuePtr(val);
00624 ptr = rb_dlptr_new(str, RSTRING_LEN(val), NULL);
00625 }
00626 else if ((vptr = rb_check_funcall(val, id_to_ptr, 0, 0)) != Qundef){
00627 if (rb_obj_is_kind_of(vptr, rb_cDLCPtr)){
00628 ptr = vptr;
00629 wrap = 0;
00630 }
00631 else{
00632 rb_raise(rb_eDLError, "to_ptr should return a CPtr object");
00633 }
00634 }
00635 else{
00636 VALUE num = rb_Integer(val);
00637 if (num == val) wrap = 0;
00638 ptr = rb_dlptr_new(NUM2PTR(num), 0, NULL);
00639 }
00640 OBJ_INFECT(ptr, val);
00641 if (wrap) RPTR_DATA(ptr)->wrap[0] = wrap;
00642 return ptr;
00643 }
00644
00645 void
00646 Init_dlptr(void)
00647 {
00648 id_to_ptr = rb_intern("to_ptr");
00649
00650
00651
00652
00653
00654
00655 rb_cDLCPtr = rb_define_class_under(rb_mDL, "CPtr", rb_cObject);
00656 rb_define_alloc_func(rb_cDLCPtr, rb_dlptr_s_allocate);
00657 rb_define_singleton_method(rb_cDLCPtr, "malloc", rb_dlptr_s_malloc, -1);
00658 rb_define_singleton_method(rb_cDLCPtr, "to_ptr", rb_dlptr_s_to_ptr, 1);
00659 rb_define_singleton_method(rb_cDLCPtr, "[]", rb_dlptr_s_to_ptr, 1);
00660 rb_define_method(rb_cDLCPtr, "initialize", rb_dlptr_initialize, -1);
00661 rb_define_method(rb_cDLCPtr, "free=", rb_dlptr_free_set, 1);
00662 rb_define_method(rb_cDLCPtr, "free", rb_dlptr_free_get, 0);
00663 rb_define_method(rb_cDLCPtr, "to_i", rb_dlptr_to_i, 0);
00664 rb_define_method(rb_cDLCPtr, "to_int", rb_dlptr_to_i, 0);
00665 rb_define_method(rb_cDLCPtr, "to_value", rb_dlptr_to_value, 0);
00666 rb_define_method(rb_cDLCPtr, "ptr", rb_dlptr_ptr, 0);
00667 rb_define_method(rb_cDLCPtr, "+@", rb_dlptr_ptr, 0);
00668 rb_define_method(rb_cDLCPtr, "ref", rb_dlptr_ref, 0);
00669 rb_define_method(rb_cDLCPtr, "-@", rb_dlptr_ref, 0);
00670 rb_define_method(rb_cDLCPtr, "null?", rb_dlptr_null_p, 0);
00671 rb_define_method(rb_cDLCPtr, "to_s", rb_dlptr_to_s, -1);
00672 rb_define_method(rb_cDLCPtr, "to_str", rb_dlptr_to_str, -1);
00673 rb_define_method(rb_cDLCPtr, "inspect", rb_dlptr_inspect, 0);
00674 rb_define_method(rb_cDLCPtr, "<=>", rb_dlptr_cmp, 1);
00675 rb_define_method(rb_cDLCPtr, "==", rb_dlptr_eql, 1);
00676 rb_define_method(rb_cDLCPtr, "eql?", rb_dlptr_eql, 1);
00677 rb_define_method(rb_cDLCPtr, "+", rb_dlptr_plus, 1);
00678 rb_define_method(rb_cDLCPtr, "-", rb_dlptr_minus, 1);
00679 rb_define_method(rb_cDLCPtr, "[]", rb_dlptr_aref, -1);
00680 rb_define_method(rb_cDLCPtr, "[]=", rb_dlptr_aset, -1);
00681 rb_define_method(rb_cDLCPtr, "size", rb_dlptr_size_get, 0);
00682 rb_define_method(rb_cDLCPtr, "size=", rb_dlptr_size_set, 1);
00683
00684
00685
00686
00687
00688 rb_define_const(rb_mDL, "NULL", rb_dlptr_new(0, 0, 0));
00689 }
00690