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