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