ext/dl/ptr.c


DEFINITIONS

This source file includes following functions.
  1. rb_hash_delete
  2. rb_dlmem_delete
  3. rb_dlmem_aset
  4. rb_dlmem_aref
  5. dlptr_free
  6. dlptr_init
  7. rb_dlptr_new2
  8. rb_dlptr_new
  9. rb_dlptr_malloc
  10. rb_dlptr2cptr
  11. rb_dlptr_s_allocate
  12. rb_dlptr_initialize
  13. rb_dlptr_s_malloc
  14. rb_dlptr_to_i
  15. rb_dlptr_ptr
  16. rb_dlptr_ref
  17. rb_dlptr_null_p
  18. rb_dlptr_free_set
  19. rb_dlptr_free_get
  20. rb_dlptr_to_array
  21. rb_dlptr_to_s
  22. rb_dlptr_to_str
  23. rb_dlptr_inspect
  24. rb_dlptr_eql
  25. rb_dlptr_cmp
  26. rb_dlptr_plus
  27. rb_dlptr_minus
  28. rb_dlptr_define_data_type
  29. rb_dlptr_define_struct
  30. rb_dlptr_define_union
  31. rb_dlptr_get_data_type
  32. cary2ary
  33. rb_dlptr_aref
  34. ary2cary
  35. rb_dlptr_aset
  36. rb_dlptr_size
  37. dlmem_each_i
  38. rb_dlmem_each
  39. Init_dlptr


   1  /* -*- C -*-
   2   * $Id: ptr.c,v 1.10 2002/08/29 13:00:22 ttate Exp $
   3   */
   4  
   5  #include <ruby.h>
   6  #include <version.h> /* for ruby version code */
   7  #include "dl.h"
   8  
   9  VALUE rb_cDLPtrData;
  10  VALUE rb_mDLMemorySpace;
  11  static VALUE DLMemoryTable;
  12  
  13  #ifndef T_SYMBOL
  14  # define T_SYMBOL T_FIXNUM
  15  #endif
  16  
  17  #if RUBY_VERSION_CODE < 171
  18  static VALUE
  19  rb_hash_delete(VALUE hash, VALUE key)
  20  {
  21    return rb_funcall(hash, rb_intern("delete"), 1, key);
  22  }
  23  #endif
  24  
  25  static void
  26  rb_dlmem_delete(void *ptr)
  27  {
  28    rb_hash_delete(DLMemoryTable, DLLONG2NUM(ptr));
  29  }
  30  
  31  static void
  32  rb_dlmem_aset(void *ptr, VALUE obj)
  33  {
  34    if( obj == Qnil ){
  35      rb_dlmem_delete(ptr);
  36    }
  37    else{
  38      rb_hash_aset(DLMemoryTable, DLLONG2NUM(ptr), DLLONG2NUM(obj));
  39    };
  40  }
  41  
  42  static VALUE
  43  rb_dlmem_aref(void *ptr)
  44  {
  45    VALUE val;
  46  
  47    val = rb_hash_aref(DLMemoryTable, DLLONG2NUM(ptr));
  48    return val == Qnil ? Qnil : (VALUE)DLNUM2LONG(val);
  49  }
  50  
  51  void
  52  dlptr_free(struct ptr_data *data)
  53  {
  54    if( data->ptr ){
  55      DEBUG_CODE({
  56        printf("dlptr_free(): removing the pointer `0x%x' from the MemorySpace\n",
  57               data->ptr);
  58      });
  59      rb_dlmem_delete(data->ptr);
  60      if( data->free ){
  61        DEBUG_CODE({
  62          printf("dlptr_free(): 0x%x(data->ptr:0x%x)\n",data->free,data->ptr);
  63        });
  64        (*(data->free))(data->ptr);
  65      };
  66    };
  67    if( data->stype ) dlfree(data->stype);
  68    if( data->ssize ) dlfree(data->ssize);
  69    if( data->ids  ) dlfree(data->ids);
  70  }
  71  
  72  void
  73  dlptr_init(VALUE val)
  74  {
  75    struct ptr_data *data;
  76  
  77    Data_Get_Struct(val, struct ptr_data, data);
  78    DEBUG_CODE({
  79      printf("dlptr_init(): add the pointer `0x%x' to the MemorySpace\n",
  80             data->ptr);
  81    });
  82    rb_dlmem_aset(data->ptr, val);
  83  }
  84  
  85  VALUE
  86  rb_dlptr_new2(VALUE klass, void *ptr, long size, freefunc_t func)
  87  {
  88    struct ptr_data *data;
  89    VALUE val;
  90  
  91    if( ptr ){
  92      val = rb_dlmem_aref(ptr);
  93      if( val == Qnil ){
  94        val = Data_Make_Struct(klass, struct ptr_data,
  95                               0, dlptr_free, data);
  96        data->ptr = ptr;
  97        data->free = func;
  98        data->ctype = DLPTR_CTYPE_UNKNOWN;
  99        data->stype = NULL;
 100        data->ssize = NULL;
 101        data->slen = 0;
 102        data->size = size;
 103        data->ids = NULL;
 104        data->ids_num = 0;
 105        dlptr_init(val);
 106      }
 107      else{
 108        if( func ){
 109          Data_Get_Struct(val, struct ptr_data, data);
 110          data->free = func;
 111        };
 112      };
 113    }
 114    else{
 115      val = Qnil;
 116    };
 117  
 118    return val;
 119  }
 120  
 121  VALUE
 122  rb_dlptr_new(void *ptr, long size, freefunc_t func)
 123  {
 124    return rb_dlptr_new2(rb_cDLPtrData, ptr, size, func);
 125  }
 126  
 127  VALUE
 128  rb_dlptr_malloc(long size, freefunc_t func)
 129  {
 130    void *ptr;
 131  
 132    ptr = dlmalloc((size_t)size);
 133    memset(ptr,0,(size_t)size);
 134    return rb_dlptr_new(ptr, size, func);
 135  }
 136  
 137  void *
 138  rb_dlptr2cptr(VALUE val)
 139  {
 140    struct ptr_data *data;
 141    void *ptr;
 142  
 143    if( rb_obj_is_kind_of(val, rb_cDLPtrData) ){
 144      Data_Get_Struct(val, struct ptr_data, data);
 145      ptr = data->ptr;
 146    }
 147    else if( val == Qnil ){
 148      ptr = NULL;
 149    }
 150    else{
 151      rb_raise(rb_eTypeError, "DL::PtrData was expected");
 152    };
 153      
 154    return ptr;
 155  }
 156  
 157  static VALUE
 158  rb_dlptr_s_allocate(VALUE klass)
 159  {
 160    VALUE obj;
 161    struct ptr_data *data;
 162  
 163    obj = Data_Make_Struct(klass, struct ptr_data, 0, dlptr_free, data);
 164    data->ptr = 0;
 165    data->free = 0;
 166    data->ctype = DLPTR_CTYPE_UNKNOWN;
 167    data->stype = NULL;
 168    data->ssize = NULL;
 169    data->slen  = 0;
 170    data->size  = 0;
 171    data->ids   = NULL;
 172    data->ids_num = 0;
 173  
 174    return obj;
 175  }
 176  
 177  static VALUE
 178  rb_dlptr_initialize(int argc, VALUE argv[], VALUE self)
 179  {
 180    VALUE ptr, sym, obj, size;
 181    struct ptr_data *data;
 182    void *p = NULL;
 183    freefunc_t f = NULL;
 184    long s = 0;
 185  
 186    switch( rb_scan_args(argc, argv, "12", &ptr, &size, &sym) ){
 187    case 1:
 188      p = (void*)(DLNUM2LONG(rb_Integer(ptr)));
 189      break;
 190    case 2:
 191      p = (void*)(DLNUM2LONG(rb_Integer(ptr)));
 192      s = DLNUM2LONG(size);
 193      break;
 194    case 3:
 195      p = (void*)(DLNUM2LONG(rb_Integer(ptr)));
 196      s = DLNUM2LONG(size);
 197      f = rb_dlsym2csym(sym);
 198      break;
 199    default:
 200      rb_bug("rb_dlptr_s_new");
 201    };
 202  
 203    if( p ){
 204      Data_Get_Struct(self, struct ptr_data, data);
 205      if( data->ptr && data->free ){
 206        /* Free previous memory. Use of inappropriate initialize may cause SEGV. */
 207        (*(data->free))(data->ptr);
 208      }
 209      data->ptr  = p;
 210      data->size = s;
 211      data->free = f;
 212    }
 213  
 214    return Qnil;
 215  }
 216  
 217  static VALUE
 218  rb_dlptr_s_malloc(int argc, VALUE argv[], VALUE klass)
 219  {
 220    VALUE size, sym, obj;
 221    int   s;
 222    freefunc_t f = NULL;
 223  
 224    switch( rb_scan_args(argc, argv, "11", &size, &sym) ){
 225    case 1:
 226      s = NUM2INT(size);
 227      break;
 228    case 2:
 229      s = NUM2INT(size);
 230      f = rb_dlsym2csym(sym);
 231      break;
 232    default:
 233      rb_bug("rb_dlptr_s_new");
 234    };
 235  
 236    obj = rb_dlptr_malloc(s,f);
 237  
 238    return obj;
 239  }
 240  
 241  VALUE
 242  rb_dlptr_to_i(VALUE self)
 243  {
 244    struct ptr_data *data;
 245  
 246    Data_Get_Struct(self, struct ptr_data, data);
 247    return DLLONG2NUM(data->ptr);
 248  }
 249  
 250  VALUE
 251  rb_dlptr_ptr(VALUE self)
 252  {
 253    struct ptr_data *data;
 254  
 255    Data_Get_Struct(self, struct ptr_data, data);
 256    return rb_dlptr_new(*((void**)(data->ptr)),0,0);
 257  }
 258  
 259  VALUE
 260  rb_dlptr_ref(VALUE self)
 261  {
 262    struct ptr_data *data;
 263  
 264    Data_Get_Struct(self, struct ptr_data, data);
 265    return rb_dlptr_new(&(data->ptr),0,0);
 266  }
 267  
 268  VALUE
 269  rb_dlptr_null_p(VALUE self)
 270  {
 271    struct ptr_data *data;
 272  
 273    Data_Get_Struct(self, struct ptr_data, data);
 274    return data->ptr ? Qfalse : Qtrue;
 275  }
 276  
 277  VALUE
 278  rb_dlptr_free_set(VALUE self, VALUE val)
 279  {
 280    struct ptr_data *data;
 281    int i;
 282  
 283    Data_Get_Struct(self, struct ptr_data, data);
 284  
 285    data->free = DLFREEFUNC(rb_dlsym2csym(val));
 286  
 287    return Qnil;
 288  }
 289  
 290  VALUE
 291  rb_dlptr_free_get(VALUE self)
 292  {
 293    struct ptr_data *pdata;
 294  
 295    Data_Get_Struct(self, struct ptr_data, pdata);
 296  
 297    return rb_dlsym_new(pdata->free,"(free)","0P");
 298  }
 299  
 300  VALUE
 301  rb_dlptr_to_array(int argc, VALUE argv[], VALUE self)
 302  {
 303    struct ptr_data *data;
 304    int n;
 305    int i;
 306    int t;
 307    VALUE ary;
 308    VALUE type, size;
 309  
 310    Data_Get_Struct(self, struct ptr_data, data);
 311  
 312    switch( rb_scan_args(argc, argv, "11", &type, &size) ){
 313    case 2:
 314      t = StringValuePtr(type)[0];
 315      n = NUM2INT(size);
 316      break;
 317    case 1:
 318      t = StringValuePtr(type)[0];
 319      switch( t ){
 320      case 'C':
 321        n = data->size;
 322        break;
 323      case 'H':
 324        n = data->size / sizeof(short);
 325        break;
 326      case 'I':
 327        n = data->size / sizeof(int);
 328        break;
 329      case 'L':
 330        n = data->size / sizeof(long);
 331        break;
 332      case 'F':
 333        n = data->size / sizeof(float);
 334        break;
 335      case 'D':
 336        n = data->size / sizeof(double);
 337        break;
 338      case  'S': case 'P':
 339        n = data->size / sizeof(void*);
 340        break;
 341      default:
 342        if( t == 'p' || t == 's' ){
 343          int i;
 344          for( i=0; ((void**)(data->ptr))[i]; i++ ){};
 345          n = i;
 346        }
 347        else{
 348          n = 0;
 349        };
 350      };
 351      break;
 352    default:
 353      rb_bug("rb_dlptr_to_array");
 354    };
 355  
 356    ary = rb_ary_new();
 357  
 358    for( i=0; i < n; i++ ){
 359      switch( t ){
 360      case 'C':
 361        rb_ary_push(ary, INT2NUM(((char*)(data->ptr))[i]));
 362        break;
 363      case 'H':
 364        rb_ary_push(ary, INT2NUM(((short*)(data->ptr))[i]));
 365        break;
 366      case 'I':
 367        rb_ary_push(ary, INT2NUM(((int*)(data->ptr))[i]));
 368        break;
 369      case 'L':
 370        rb_ary_push(ary, DLLONG2NUM(((long*)(data->ptr))[i]));
 371        break;
 372      case 'D':
 373        rb_ary_push(ary, rb_float_new(((double*)(data->ptr))[i]));
 374      case 'F':
 375        rb_ary_push(ary, rb_float_new(((float*)(data->ptr))[i]));
 376        break;
 377      case 'S':
 378        {
 379          char *str = ((char**)(data->ptr))[i];
 380          if( str ){
 381            rb_ary_push(ary, rb_tainted_str_new2(str));
 382          }
 383          else{
 384            rb_ary_push(ary, Qnil);
 385          };
 386        };
 387        break;
 388      case 's':
 389        {
 390          char *str = ((char**)(data->ptr))[i];
 391          if( str ){
 392            rb_ary_push(ary, rb_tainted_str_new2(str));
 393            xfree(str);
 394          }
 395          else{
 396            rb_ary_push(ary, Qnil);
 397          };
 398        };
 399        break;
 400      case 'P':
 401        rb_ary_push(ary, rb_dlptr_new(((void**)(data->ptr))[i],0,0));
 402        break;
 403      case 'p':
 404        rb_ary_push(ary,
 405                    rb_dlptr_new(((void**)(data->ptr))[i],0,dlfree));
 406        break;
 407      };
 408    };
 409  
 410    return ary;
 411  }
 412  
 413  
 414  VALUE
 415  rb_dlptr_to_s(int argc, VALUE argv[], VALUE self)
 416  {
 417    struct ptr_data *data;
 418    VALUE arg1, val;
 419    int len;
 420  
 421    Data_Get_Struct(self, struct ptr_data, data);
 422    switch( rb_scan_args(argc, argv, "01", &arg1) ){
 423    case 0:
 424      val = rb_tainted_str_new2((char*)(data->ptr));
 425      break;
 426    case 1:
 427      len = NUM2INT(arg1);
 428      val = rb_tainted_str_new((char*)(data->ptr), len);
 429      break;
 430    default:
 431      rb_bug("rb_dlptr_to_s");
 432    };
 433  
 434    return val;
 435  }
 436  
 437  VALUE
 438  rb_dlptr_to_str(int argc, VALUE argv[], VALUE self)
 439  {
 440    struct ptr_data *data;
 441    VALUE arg1, val;
 442    int len;
 443  
 444    Data_Get_Struct(self, struct ptr_data, data);
 445    switch( rb_scan_args(argc, argv, "01", &arg1) ){
 446    case 0:
 447      val = rb_tainted_str_new((char*)(data->ptr),data->size);
 448      break;
 449    case 1:
 450      len = NUM2INT(arg1);
 451      val = rb_tainted_str_new((char*)(data->ptr), len);
 452      break;
 453    default:
 454      rb_bug("rb_dlptr_to_str");
 455    };
 456  
 457    return val;
 458  }
 459  
 460  VALUE
 461  rb_dlptr_inspect(VALUE self)
 462  {
 463    struct ptr_data *data;
 464    char str[1024];
 465    VALUE name;
 466  
 467    Data_Get_Struct(self, struct ptr_data, data);
 468    snprintf(str, 1023, "#<%s:0x%x ptr=0x%x size=%ld free=0x%x>",
 469             rb_class2name(CLASS_OF(self)), data, data->ptr, data->size, data->free);
 470    return rb_str_new2(str);
 471  }
 472  
 473  VALUE
 474  rb_dlptr_eql(VALUE self, VALUE other)
 475  {
 476    void *ptr1, *ptr2;
 477    ptr1 = rb_dlptr2cptr(self);
 478    ptr2 = rb_dlptr2cptr(other);
 479  
 480    return ptr1 == ptr2 ? Qtrue : Qfalse;
 481  }
 482  
 483  VALUE
 484  rb_dlptr_cmp(VALUE self, VALUE other)
 485  {
 486    void *ptr1, *ptr2;
 487    ptr1 = rb_dlptr2cptr(self);
 488    ptr2 = rb_dlptr2cptr(other);
 489    return DLLONG2NUM((long)ptr1 - (long)ptr2);
 490  }
 491  
 492  VALUE
 493  rb_dlptr_plus(VALUE self, VALUE other)
 494  {
 495    void *ptr;
 496    long num, size;
 497  
 498    ptr = rb_dlptr2cptr(self);
 499    size = RDLPTR(self)->size;
 500    num = DLNUM2LONG(other);
 501    return rb_dlptr_new((char *)ptr + num, size - num, 0);
 502  }
 503  
 504  VALUE
 505  rb_dlptr_minus(VALUE self, VALUE other)
 506  {
 507    void *ptr;
 508    long num, size;
 509  
 510    ptr = rb_dlptr2cptr(self);
 511    size = RDLPTR(self)->size;
 512    num = DLNUM2LONG(other);
 513    return rb_dlptr_new((char *)ptr - num, size + num, 0);
 514  }
 515  
 516  VALUE
 517  rb_dlptr_define_data_type(int argc, VALUE argv[], VALUE self)
 518  {
 519    VALUE data_type, type, rest, vid;
 520    struct ptr_data *data;
 521    int i, t, len, num;
 522    char *ctype;
 523    long size;
 524  
 525    rb_scan_args(argc, argv, "11*", &data_type, &type, &rest);
 526    Data_Get_Struct(self, struct ptr_data, data);
 527  
 528    if( argc == 1 || (argc == 2 && type == Qnil) ){
 529      if( NUM2INT(data_type) == DLPTR_CTYPE_UNKNOWN ){
 530        data->ctype = DLPTR_CTYPE_UNKNOWN;
 531        data->slen = 0;
 532        data->ids_num  = 0;
 533        if( data->stype ){
 534          dlfree(data->stype);
 535          data->stype = NULL;
 536        };
 537        if( data->ids ){
 538          dlfree(data->ids);
 539          data->ids = NULL;
 540        };
 541        return Qnil;
 542      }
 543      else{
 544        rb_raise(rb_eArgError, "wrong arguments");
 545      };
 546    };
 547  
 548    t = NUM2INT(data_type);
 549    StringValue(type);
 550    Check_Type(rest, T_ARRAY);
 551    num = RARRAY(rest)->len;
 552    for( i=0; i<num; i++ ){
 553      vid = rb_ary_entry(rest,i);
 554      if( !(TYPE(vid)==T_STRING || TYPE(vid)==T_SYMBOL) ){
 555        rb_raise(rb_eTypeError, "#%d must be a string or symbol", i + 2);
 556      };
 557    };
 558  
 559    data->ctype = t;
 560    data->slen = num;
 561    data->ids_num  = num;
 562    if( data->stype ) dlfree(data->stype);
 563    data->stype = (char*)dlmalloc(sizeof(char) * num);
 564    if( data->ssize ) dlfree(data->ssize);
 565    data->ssize = (int*)dlmalloc(sizeof(int) * num);
 566    if( data->ids ) dlfree(data->ids);
 567    data->ids  = (ID*)dlmalloc(sizeof(ID) * data->ids_num);
 568  
 569    ctype = StringValuePtr(type);
 570    for( i=0; i<num; i++ ){
 571      vid = rb_ary_entry(rest,i);
 572      data->ids[i] = rb_to_id(vid);
 573      data->stype[i] = *ctype;
 574      ctype ++;
 575      if( isdigit(*ctype) ){
 576        char *p, *d;
 577        for( p=ctype; isdigit(*p); p++ ) ;
 578        d = ALLOCA_N(char, p - ctype + 1);
 579        strncpy(d, ctype, p - ctype);
 580        d[p - ctype] = '\0';
 581        data->ssize[i] = atoi(d);
 582        ctype = p;
 583      }
 584      else{
 585        data->ssize[i] = 1;
 586      };
 587    };
 588  
 589    if( *ctype ){
 590      rb_raise(rb_eArgError, "too few/many arguments");
 591    };
 592  
 593    if( !data->size )
 594      data->size = dlsizeof(RSTRING(type)->ptr);
 595  
 596    return Qnil;
 597  }
 598  
 599  VALUE
 600  rb_dlptr_define_struct(int argc, VALUE argv[], VALUE self)
 601  {
 602    VALUE *pass_argv;
 603    int pass_argc, i;
 604  
 605    pass_argc = argc + 1;
 606    pass_argv = ALLOCA_N(VALUE, pass_argc);
 607    pass_argv[0] = INT2FIX(DLPTR_CTYPE_STRUCT);
 608    for( i=1; i<pass_argc; i++ ){
 609      pass_argv[i] = argv[i-1];
 610    };
 611    return rb_dlptr_define_data_type(pass_argc, pass_argv, self);
 612  }
 613  
 614  VALUE
 615  rb_dlptr_define_union(int argc, VALUE argv[], VALUE self)
 616  {
 617    VALUE *pass_argv;
 618    int pass_argc, i;
 619  
 620    pass_argc = argc + 1;
 621    pass_argv = ALLOCA_N(VALUE, pass_argc);
 622    pass_argv[0] = INT2FIX(DLPTR_CTYPE_UNION);
 623    for( i=1; i<pass_argc; i++ ){
 624      pass_argv[i] = argv[i-1];
 625    };
 626    return rb_dlptr_define_data_type(pass_argc, pass_argv, self);
 627  }
 628  
 629  VALUE
 630  rb_dlptr_get_data_type(VALUE self)
 631  {
 632    struct ptr_data *data;
 633  
 634    Data_Get_Struct(self, struct ptr_data, data);
 635    if( data->stype )
 636      return rb_assoc_new(INT2FIX(data->ctype),
 637                          rb_tainted_str_new(data->stype, data->slen));
 638    else
 639      return rb_assoc_new(INT2FIX(data->ctype), Qnil);
 640  }
 641  
 642  static VALUE
 643  cary2ary(void *ptr, char t, int len)
 644  {
 645    VALUE ary;
 646    VALUE elem;
 647    int i;
 648  
 649    if( len < 1 )
 650      return Qnil;
 651  
 652    if( len == 1 ){
 653      switch( t ){
 654      case 'I':
 655        elem = INT2NUM(*((int*)ptr));
 656        ptr = (char *)ptr + sizeof(int);
 657        break;
 658      case 'L':
 659        elem = DLLONG2NUM(*((long*)ptr));
 660        ptr = (char *)ptr + sizeof(long);
 661        break;
 662      case 'P':
 663        elem = rb_dlptr_new(*((void**)ptr),0, 0);
 664        ptr = (char *)ptr + sizeof(void*);
 665        break;
 666      case 'F':
 667        elem = rb_float_new(*((float*)ptr));
 668        ptr = (char *)ptr + sizeof(float);
 669        break;
 670      case 'D':
 671        elem = rb_float_new(*((double*)ptr));
 672        ptr = (char *)ptr + sizeof(double);
 673        break;
 674      case 'C':
 675        elem = INT2NUM(*((char*)ptr));
 676        ptr = (char *)ptr + sizeof(char);
 677        break;
 678      case 'H':
 679        elem = INT2NUM(*((short*)ptr));
 680        ptr = (char *)ptr + sizeof(short);
 681        break;
 682      default:
 683        rb_raise(rb_eDLTypeError, "unsupported type '%c'", t);
 684      };
 685      return elem;
 686    };
 687  
 688    ary = rb_ary_new();
 689    for( i=0; i < len; i++ ){
 690      switch( t ){
 691      case 'I':
 692        elem = INT2NUM(*((int*)ptr));
 693        ptr = (char *)ptr + sizeof(int);
 694        break;
 695      case 'L':
 696        elem = DLLONG2NUM(*((long*)ptr));
 697        ptr = (char *)ptr + sizeof(long);
 698        break;
 699      case 'P':
 700        elem = rb_dlptr_new(*((void**)ptr), 0, 0);
 701        ptr = (char *)ptr + sizeof(void*);
 702        break;
 703      case 'F':
 704        elem = rb_float_new(*((float*)ptr));
 705        ptr = (char *)ptr + sizeof(float);
 706        break;
 707      case 'D':
 708        elem = rb_float_new(*((float*)ptr));
 709        ptr = (char *)ptr + sizeof(double);
 710        break;
 711      case 'C':
 712        elem = INT2NUM(*((char*)ptr));
 713        ptr = (char *)ptr + sizeof(char);
 714        break;
 715      case 'H':
 716        elem = INT2NUM(*((short*)ptr));
 717        ptr = (char *)ptr + sizeof(short);
 718        break;
 719      default:
 720        rb_raise(rb_eDLTypeError, "unsupported type '%c'", t);
 721      };
 722      rb_ary_push(ary, elem);
 723    };
 724  
 725    return ary;
 726  }
 727  
 728  VALUE
 729  rb_dlptr_aref(int argc, VALUE argv[], VALUE self)
 730  {
 731    VALUE val, key = Qnil, num = Qnil;
 732    ID id;
 733    int idx;
 734    struct ptr_data *data;
 735    int i;
 736    int offset;
 737  
 738    if( rb_scan_args(argc, argv, "11", &key, &num) == 1 ){
 739      num = INT2NUM(0);
 740    };
 741  
 742    if( TYPE(key) == T_FIXNUM || TYPE(key) == T_BIGNUM ){
 743      VALUE pass[1];
 744      pass[0] = num;
 745      return rb_dlptr_to_str(1, pass, rb_dlptr_plus(self, key));
 746    };
 747  
 748    if( ! (TYPE(key) == T_STRING || TYPE(key) == T_SYMBOL ) ){
 749      rb_raise(rb_eTypeError, "the key must be a string or symbol");
 750    };
 751  
 752    id = rb_to_id(key);
 753    Data_Get_Struct(self, struct ptr_data, data);
 754    offset = 0;
 755    switch( data->ctype ){
 756    case DLPTR_CTYPE_STRUCT:
 757      for( i=0; i < data->ids_num; i++ ){
 758        if( data->ids[i] == id ){
 759          switch( data->stype[i] ){
 760          case 'I':
 761            DLALIGN(data->ptr,offset,INT_ALIGN);
 762            break;
 763          case 'L':
 764            DLALIGN(data->ptr,offset,LONG_ALIGN);
 765            break;
 766          case 'P':
 767            DLALIGN(data->ptr,offset,VOIDP_ALIGN);
 768            break;
 769          case 'F':
 770            DLALIGN(data->ptr,offset,FLOAT_ALIGN);
 771            break;
 772          case 'D':
 773            DLALIGN(data->ptr,offset,DOUBLE_ALIGN);
 774            break;
 775          case 'C':
 776            break;
 777          case 'H':
 778            DLALIGN(data->ptr,offset,SHORT_ALIGN);
 779            break;
 780          default:
 781            rb_raise(rb_eDLTypeError, "unsupported type '%c'", data->stype[i]);
 782          };
 783          return cary2ary((char *)data->ptr + offset, data->stype[i], data->ssize[i]);
 784        };
 785        switch( data->stype[i] ){
 786        case 'I':
 787          offset += sizeof(int) * data->ssize[i];
 788          break;
 789        case 'L':
 790          offset += sizeof(long) * data->ssize[i];
 791          break;
 792        case 'P':
 793          offset += sizeof(void*) * data->ssize[i];
 794          break;
 795        case 'F':
 796          offset += sizeof(float) * data->ssize[i];
 797          break;
 798        case 'D':
 799          offset += sizeof(double) * data->ssize[i];
 800          break;
 801        case 'C':
 802          offset += sizeof(char) * data->ssize[i];
 803          break;
 804        case 'H':
 805          offset += sizeof(short) * data->ssize[i];
 806          break;
 807        default:
 808          rb_raise(rb_eDLTypeError, "unsupported type '%c'", data->stype[i]);
 809        };
 810      };
 811      break;
 812    case DLPTR_CTYPE_UNION:
 813      for( i=0; i < data->ids_num; i++ ){
 814        if( data->ids[i] == id ){
 815          return cary2ary((char *)data->ptr + offset, data->stype[i], data->ssize[i]);
 816        };
 817      };
 818      break;
 819    }; /* end of switch */
 820  
 821    rb_raise(rb_eNameError, "undefined key `%s' for %s",
 822             rb_id2name(id), rb_class2name(CLASS_OF(self)));
 823  
 824    return Qnil;
 825  }
 826  
 827  static void *
 828  ary2cary(char t, VALUE val, long *size)
 829  {
 830    void *ptr;
 831  
 832    if( TYPE(val) == T_ARRAY ){
 833      ptr = rb_ary2cary(t, val, size);
 834    }
 835    else{
 836      ptr = rb_ary2cary(t, rb_ary_new3(1, val), size);
 837    };
 838    return ptr;
 839  }
 840  
 841  VALUE
 842  rb_dlptr_aset(int argc, VALUE argv[], VALUE self)
 843  {
 844    VALUE key = Qnil, num = Qnil, val = Qnil;
 845    ID id;
 846    struct ptr_data *data;
 847    int i;
 848    int offset;
 849    long memsize;
 850    void *memimg;
 851  
 852    switch( rb_scan_args(argc, argv, "21", &key, &num, &val) ){
 853    case 2:
 854      val = num;
 855      num = Qnil;
 856      break;
 857    };
 858  
 859    if( TYPE(key) == T_FIXNUM || TYPE(key) == T_BIGNUM ){
 860      void *dst, *src;
 861      long len;
 862  
 863      StringValue(val);
 864      Data_Get_Struct(self, struct ptr_data, data);
 865      dst = (void*)((long)(data->ptr) + DLNUM2LONG(key));
 866      src = RSTRING(val)->ptr;
 867      len = RSTRING(val)->len;
 868      if( num == Qnil ){
 869        memcpy(dst, src, len);
 870      }
 871      else{
 872        long n = NUM2INT(num);
 873        memcpy(dst, src, n < len ? n : len);
 874        if( n > len ) MEMZERO((char*)dst + len, char, n - len);
 875      };
 876      return val;
 877    };
 878  
 879    if( ! (TYPE(key) == T_STRING || TYPE(key) == T_SYMBOL ) ){
 880      rb_raise(rb_eTypeError, "the key must be a string or symbol");
 881    };
 882  
 883    id = rb_to_id(key);
 884    Data_Get_Struct(self, struct ptr_data, data);
 885    switch( data->ctype ){
 886    case DLPTR_CTYPE_STRUCT:
 887      offset = 0;
 888      for( i=0; i < data->ids_num; i++ ){
 889        if( data->ids[i] == id ){
 890          switch( data->stype[i] ){
 891          case 'I':
 892            DLALIGN(data->ptr,offset,INT_ALIGN);
 893            break;
 894          case 'L':
 895            DLALIGN(data->ptr,offset,LONG_ALIGN);
 896            break;
 897          case 'P':
 898            DLALIGN(data->ptr,offset,VOIDP_ALIGN);
 899            break;
 900          case 'D':
 901            DLALIGN(data->ptr,offset,DOUBLE_ALIGN);
 902            break;
 903          case 'F':
 904            DLALIGN(data->ptr,offset,FLOAT_ALIGN);
 905            break;
 906          case 'C':
 907            break;
 908          case 'H':
 909            DLALIGN(data->ptr,offset,SHORT_ALIGN);
 910            break;
 911          default:
 912            rb_raise(rb_eDLTypeError, "unsupported type '%c'", data->stype[i]);
 913          };
 914          memimg = ary2cary(data->stype[i], val, &memsize);
 915          memcpy((char *)data->ptr + offset, memimg, memsize);
 916          return val;
 917        };
 918        switch( data->stype[i] ){
 919        case 'I':
 920        case 'i':
 921          offset += sizeof(int) * data->ssize[i];
 922          break;
 923        case 'L':
 924        case 'l':
 925          offset += sizeof(long) * data->ssize[i];
 926          break;
 927        case 'P':
 928        case 'p':
 929          offset += sizeof(void*) * data->ssize[i];
 930          break;
 931        case 'D':
 932        case 'd':
 933          offset += sizeof(double) * data->ssize[i];
 934          break;
 935        case 'F':
 936        case 'f':
 937          offset += sizeof(float) * data->ssize[i];
 938          break;
 939        case 'C':
 940        case 'c':
 941          offset += sizeof(char) * data->ssize[i];
 942          break;
 943        case 'H':
 944        case 'h':
 945          offset += sizeof(short) * data->ssize[i];
 946          break;
 947        default:
 948          rb_raise(rb_eDLTypeError, "unsupported type '%c'", data->stype[i]);
 949        };
 950      };
 951      return val;
 952      /* break; */
 953    case DLPTR_CTYPE_UNION:
 954      for( i=0; i < data->ids_num; i++ ){
 955        if( data->ids[i] == id ){
 956          switch( data->stype[i] ){
 957          case 'I': case 'i':
 958            memsize = sizeof(int) * data->ssize[i];
 959            break;
 960          case 'L': case 'l':
 961            memsize = sizeof(long) * data->ssize[i];
 962            break;
 963          case 'P': case 'p':
 964            memsize = sizeof(void*) * data->ssize[i];
 965            break;
 966          case 'F': case 'f':
 967            memsize = sizeof(float) * data->ssize[i];
 968            break;
 969          case 'D': case 'd':
 970            memsize = sizeof(double) * data->ssize[i];
 971            break;
 972          case 'C': case 'c':
 973            memsize = sizeof(char) * data->ssize[i];
 974            break;
 975          case 'H': case 'h':
 976            memsize = sizeof(short) * data->ssize[i];
 977            break;
 978          default:
 979            rb_raise(rb_eDLTypeError, "unsupported type '%c'", data->stype[i]);
 980          };
 981          memimg = ary2cary(data->stype[i], val, NULL);
 982          memcpy(data->ptr, memimg, memsize);
 983        };
 984      };
 985      return val;
 986      /* break; */
 987    };
 988  
 989    rb_raise(rb_eNameError, "undefined key `%s' for %s",
 990             rb_id2name(id), rb_class2name(CLASS_OF(self)));
 991  
 992    return Qnil;
 993  }
 994  
 995  VALUE
 996  rb_dlptr_size(int argc, VALUE argv[], VALUE self)
 997  {
 998    VALUE size;
 999  
1000    if( rb_scan_args(argc, argv, "01", &size) == 0){
1001      return DLLONG2NUM(RDLPTR(self)->size);
1002    }
1003    else{
1004      RDLPTR(self)->size = DLNUM2LONG(size);
1005      return size;
1006    };
1007  }
1008  
1009  static VALUE
1010  dlmem_each_i(VALUE assoc, void *data)
1011  {
1012    VALUE key, val;
1013    key = rb_ary_entry(assoc, 0);
1014    val = rb_ary_entry(assoc, 1);
1015    rb_yield(rb_assoc_new(key,(VALUE)DLNUM2LONG(val)));
1016    return Qnil;
1017  }
1018  
1019  VALUE
1020  rb_dlmem_each(VALUE self)
1021  {
1022    rb_iterate(rb_each, DLMemoryTable, dlmem_each_i, 0);
1023    return Qnil;
1024  }
1025  
1026  void
1027  Init_dlptr()
1028  {
1029    rb_cDLPtrData = rb_define_class_under(rb_mDL, "PtrData", rb_cObject);
1030    rb_define_singleton_method(rb_cDLPtrData, "allocate", rb_dlptr_s_allocate, 0);
1031    rb_define_singleton_method(rb_cDLPtrData, "malloc", rb_dlptr_s_malloc, -1);
1032    rb_define_method(rb_cDLPtrData, "initialize", rb_dlptr_initialize, -1);
1033    rb_define_method(rb_cDLPtrData, "free=", rb_dlptr_free_set, 1);
1034    rb_define_method(rb_cDLPtrData, "free",  rb_dlptr_free_get, 0);
1035    rb_define_method(rb_cDLPtrData, "to_i",  rb_dlptr_to_i, 0);
1036    rb_define_method(rb_cDLPtrData, "ptr",   rb_dlptr_ptr, 0);
1037    rb_define_method(rb_cDLPtrData, "+@", rb_dlptr_ptr, 0);
1038    rb_define_method(rb_cDLPtrData, "ref",   rb_dlptr_ref, 0);
1039    rb_define_method(rb_cDLPtrData, "-@", rb_dlptr_ref, 0);
1040    rb_define_method(rb_cDLPtrData, "null?", rb_dlptr_null_p, 0);
1041    rb_define_method(rb_cDLPtrData, "to_a", rb_dlptr_to_array, -1);
1042    rb_define_method(rb_cDLPtrData, "to_s", rb_dlptr_to_s, -1);
1043    rb_define_method(rb_cDLPtrData, "to_str", rb_dlptr_to_str, -1);
1044    rb_define_method(rb_cDLPtrData, "inspect", rb_dlptr_inspect, 0);
1045    rb_define_method(rb_cDLPtrData, "<=>", rb_dlptr_cmp, 1);
1046    rb_define_method(rb_cDLPtrData, "==", rb_dlptr_eql, 1);
1047    rb_define_method(rb_cDLPtrData, "eql?", rb_dlptr_eql, 1);
1048    rb_define_method(rb_cDLPtrData, "+", rb_dlptr_plus, 1);
1049    rb_define_method(rb_cDLPtrData, "-", rb_dlptr_minus, 1);
1050    rb_define_method(rb_cDLPtrData, "define_data_type",
1051                     rb_dlptr_define_data_type, -1);
1052    rb_define_method(rb_cDLPtrData, "struct!", rb_dlptr_define_struct, -1);
1053    rb_define_method(rb_cDLPtrData, "union!",  rb_dlptr_define_union,  -1);
1054    rb_define_method(rb_cDLPtrData, "data_type", rb_dlptr_get_data_type, 0);
1055    rb_define_method(rb_cDLPtrData, "[]", rb_dlptr_aref, -1);
1056    rb_define_method(rb_cDLPtrData, "[]=", rb_dlptr_aset, -1);
1057    rb_define_method(rb_cDLPtrData, "size", rb_dlptr_size, -1);
1058    rb_define_method(rb_cDLPtrData, "size=", rb_dlptr_size, -1);
1059  
1060    rb_mDLMemorySpace = rb_define_module_under(rb_mDL, "MemorySpace");
1061    DLMemoryTable = rb_hash_new();
1062    rb_define_const(rb_mDLMemorySpace, "MemoryTable", DLMemoryTable);
1063    rb_define_module_function(rb_mDLMemorySpace, "each", rb_dlmem_each, 0);
1064  }