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