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