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