ext/dl/dl.c


DEFINITIONS

This source file includes following functions.
  1. rb_dl_scan_callback_args
  2. init_dl_func_table
  3. dlmalloc
  4. dlrealloc
  5. dlfree
  6. dlstrdup
  7. dlsizeof
  8. c_farray
  9. c_darray
  10. c_larray
  11. c_iarray
  12. c_harray
  13. c_carray
  14. c_parray
  15. rb_ary2cary
  16. rb_str_to_ptr
  17. rb_ary_to_ptr
  18. rb_io_to_ptr
  19. rb_dl_dlopen
  20. rb_dl_malloc
  21. rb_dl_strdup
  22. rb_dl_sizeof
  23. rb_dl_callback
  24. rb_dl_remove_callback
  25. Init_dl


   1  /*
   2   * $Id: dl.c,v 1.12 2002/08/04 13:49:13 ttate Exp $
   3   */
   4  
   5  #include <ruby.h>
   6  #include <rubyio.h>
   7  #include <ctype.h>
   8  #include "dl.h"
   9  
  10  VALUE rb_mDL;
  11  VALUE rb_eDLError;
  12  VALUE rb_eDLTypeError;
  13  
  14  static VALUE DLFuncTable;
  15  static void *rb_dl_callback_table[CALLBACK_TYPES][MAX_CALLBACK];
  16  static ID id_call;
  17  
  18  static int
  19  rb_dl_scan_callback_args(long stack[], const char *proto,
  20                           int *argc, VALUE argv[])
  21  {
  22    int i;
  23    long *sp;
  24    VALUE val;
  25  
  26    sp = stack;
  27    for( i=1; proto[i]; i++ ){
  28      switch( proto[i] ){
  29      case 'C':
  30        {
  31          char v;
  32          v = (char)(*sp);
  33          sp++;
  34          val = INT2NUM(v);
  35        }
  36        break;
  37      case 'H':
  38        {
  39          short v;
  40          v = (short)(*sp);
  41          sp++;
  42          val = INT2NUM(v);
  43        }
  44        break;
  45      case 'I':
  46        {
  47          int v;
  48          v = (int)(*sp);
  49          sp++;
  50          val = INT2NUM(v);
  51        }
  52        break;
  53      case 'L':
  54        {
  55          long v;
  56          v = (long)(*sp);
  57          sp++;
  58          val = INT2NUM(v);
  59        }
  60        break;
  61      case 'F':
  62        {
  63          float v;
  64          memcpy(&v, sp, sizeof(float));
  65          sp += sizeof(float)/sizeof(long);
  66          val = rb_float_new(v);
  67        }
  68        break;
  69      case 'D':
  70        {
  71          double v;
  72          memcpy(&v, sp, sizeof(double));
  73          sp += sizeof(double)/sizeof(long);
  74          val = rb_float_new(v);
  75        }
  76        break;
  77      case 'P':
  78        {
  79          void *v;
  80          memcpy(&v, sp, sizeof(void*));
  81          sp++;
  82          val = rb_dlptr_new(v, 0, 0);
  83        }
  84        break;
  85      case 'S':
  86        {
  87          char *v;
  88          memcpy(&v, sp, sizeof(void*));
  89          sp++;
  90          val = rb_tainted_str_new2(v);
  91        }
  92        break;
  93      default:
  94        rb_raise(rb_eDLTypeError, "unsupported type `%c'", proto[i]);
  95        break;
  96      }
  97      argv[i-1] = val;
  98    }
  99    *argc = (i - 1);
 100  
 101    return (*argc);
 102  }
 103  
 104  #include "callback.func"
 105  
 106  static void
 107  init_dl_func_table(){
 108  #include "cbtable.func"
 109  }
 110  
 111  void *
 112  dlmalloc(size_t size)
 113  {
 114    DEBUG_CODE2({
 115      void *ptr;
 116  
 117      printf("dlmalloc(%d)",size);
 118      ptr = xmalloc(size);
 119      printf(":0x%x\n",ptr);
 120      return ptr;
 121    },
 122    {
 123      return xmalloc(size);
 124    });
 125  }
 126  
 127  void *
 128  dlrealloc(void *ptr, size_t size)
 129  {
 130    DEBUG_CODE({
 131      printf("dlrealloc(0x%x,%d)\n",ptr,size);
 132    });
 133    return xrealloc(ptr, size);
 134  }
 135  
 136  void
 137  dlfree(void *ptr)
 138  {
 139    DEBUG_CODE({
 140      printf("dlfree(0x%x)\n",ptr);
 141    });
 142    xfree(ptr);
 143  }
 144  
 145  char*
 146  dlstrdup(const char *str)
 147  {
 148    char *newstr;
 149  
 150    newstr = (char*)dlmalloc(strlen(str));
 151    strcpy(newstr,str);
 152  
 153    return newstr;
 154  }
 155  
 156  size_t
 157  dlsizeof(const char *cstr)
 158  {
 159    size_t size;
 160    int i, len, n, dlen;
 161    char *d;
 162  
 163    len  = strlen(cstr);
 164    size = 0;
 165    for( i=0; i<len; i++ ){
 166      n = 1;
 167      if( isdigit(cstr[i+1]) ){
 168        dlen = 1;
 169        while( isdigit(cstr[i+dlen]) ){ dlen ++; };
 170        dlen --;
 171        d = ALLOCA_N(char, dlen + 1);
 172        strncpy(d, cstr + i + 1, dlen);
 173        d[dlen] = '\0';
 174        n = atoi(d);
 175      }
 176      else{
 177        dlen = 0;
 178      };
 179  
 180      switch( cstr[i] ){
 181      case 'I':
 182        DLALIGN(0,size,INT_ALIGN);
 183      case 'i':
 184        size += sizeof(int) * n;
 185        break;
 186      case 'L':
 187        DLALIGN(0,size,LONG_ALIGN);
 188      case 'l':
 189        size += sizeof(long) * n;
 190        break;
 191      case 'F':
 192        DLALIGN(0,size,FLOAT_ALIGN);
 193      case 'f':
 194        size += sizeof(float) * n;
 195        break;
 196      case 'D':
 197        DLALIGN(0,size,DOUBLE_ALIGN);
 198      case 'd':
 199        size += sizeof(double) * n;
 200        break;
 201      case 'C':
 202      case 'c':
 203        size += sizeof(char) * n;
 204        break;
 205      case 'H':
 206        DLALIGN(0,size,SHORT_ALIGN);
 207      case 'h':
 208        size += sizeof(short) * n;
 209        break;
 210      case 'P':
 211        DLALIGN(0,size,VOIDP_ALIGN);
 212      case 'p':
 213        size += sizeof(void*) * n;
 214        break;
 215      default:
 216        rb_raise(rb_eDLTypeError, "unexpected type '%c'", cstr[i]);
 217        break;
 218      };
 219      i += dlen;
 220    };
 221  
 222    return size;
 223  }
 224  
 225  static float *
 226  c_farray(VALUE v, long *size)
 227  {
 228    int i, len;
 229    float *ary;
 230    VALUE e;
 231  
 232    len = RARRAY(v)->len;
 233    *size = sizeof(float) * len;
 234    ary = dlmalloc(*size);
 235    for( i=0; i < len; i++ ){
 236      e = rb_ary_entry(v, i);
 237      switch( TYPE(e) ){
 238      case T_FLOAT:
 239        ary[i] = (float)(RFLOAT(e)->value);
 240        break;
 241      case T_NIL:
 242        ary[i] = 0.0;
 243        break;
 244      default:
 245        rb_raise(rb_eDLTypeError, "unexpected type of the element #%d", i);
 246        break;
 247      };
 248    };
 249  
 250    return ary;
 251  }
 252  
 253  static double *
 254  c_darray(VALUE v, long *size)
 255  {
 256    int i, len;
 257    double *ary;
 258    VALUE e;
 259  
 260    len = RARRAY(v)->len;
 261    *size = sizeof(double) * len;
 262    ary = dlmalloc(*size);
 263    for( i=0; i < len; i++ ){
 264      e = rb_ary_entry(v, i);
 265      switch( TYPE(e) ){
 266      case T_FLOAT:
 267        ary[i] = (double)(RFLOAT(e)->value);
 268        break;
 269      case T_NIL:
 270        ary[i] = 0.0;
 271        break;
 272      default:
 273        rb_raise(rb_eDLTypeError, "unexpected type of the element #%d", i);
 274        break;
 275      };
 276    };
 277  
 278    return ary;
 279  }
 280  
 281  static long *
 282  c_larray(VALUE v, long *size)
 283  {
 284    int i, len;
 285    long *ary;
 286    VALUE e;
 287  
 288    len = RARRAY(v)->len;
 289    *size = sizeof(long) * len;
 290    ary = dlmalloc(*size);
 291    for( i=0; i < len; i++ ){
 292      e = rb_ary_entry(v, i);
 293      switch( TYPE(e) ){
 294      case T_FIXNUM:
 295      case T_BIGNUM:
 296        ary[i] = (long)(NUM2INT(e));
 297        break;
 298      case T_NIL:
 299        ary[i] = 0;
 300        break;
 301      default:
 302        rb_raise(rb_eDLTypeError, "unexpected type of the element #%d", i);
 303        break;
 304      };
 305    };
 306  
 307    return ary;
 308  }
 309  
 310  static int *
 311  c_iarray(VALUE v, long *size)
 312  {
 313    int i, len;
 314    int *ary;
 315    VALUE e;
 316  
 317    len = RARRAY(v)->len;
 318    *size = sizeof(int) * len;
 319    ary = dlmalloc(*size);
 320    for( i=0; i < len; i++ ){
 321      e = rb_ary_entry(v, i);
 322      switch( TYPE(e) ){
 323      case T_FIXNUM:
 324      case T_BIGNUM:
 325        ary[i] = (int)(NUM2INT(e));
 326        break;
 327      case T_NIL:
 328        ary[i] = 0;
 329        break;
 330      default:
 331        rb_raise(rb_eDLTypeError, "unexpected type of the element #%d", i);
 332        break;
 333      };
 334    };
 335  
 336    return ary;
 337  }
 338  
 339  static short *
 340  c_harray(VALUE v, long *size)
 341  {
 342    int i, len;
 343    short *ary;
 344    VALUE e;
 345  
 346    len = RARRAY(v)->len;
 347    *size = sizeof(short) * len;
 348    ary = dlmalloc(*size);
 349    for( i=0; i < len; i++ ){
 350      e = rb_ary_entry(v, i);
 351      switch( TYPE(e) ){
 352      case T_FIXNUM:
 353      case T_BIGNUM:
 354        ary[i] = (short)(NUM2INT(e));
 355        break;
 356      case T_NIL:
 357        ary[i] = 0;
 358        break;
 359      default:
 360        rb_raise(rb_eDLTypeError, "unexpected type of the element #%d", i);
 361        break;
 362      };
 363    };
 364  
 365    return ary;
 366  }
 367  
 368  static char *
 369  c_carray(VALUE v, long *size)
 370  {
 371    int i, len;
 372    char *ary;
 373    VALUE e;
 374  
 375    len = RARRAY(v)->len;
 376    *size = sizeof(char) * len;
 377    ary = dlmalloc(*size);
 378    for( i=0; i < len; i++ ){
 379      e = rb_ary_entry(v, i);
 380      switch( TYPE(e) ){
 381      case T_FIXNUM:
 382      case T_BIGNUM:
 383        ary[i] = (char)(NUM2INT(e));
 384        break;
 385      case T_NIL:
 386        ary[i] = 0;
 387        break;
 388      default:
 389        rb_raise(rb_eDLTypeError, "unexpected type of the element #%d", i);
 390        break;
 391      };
 392    };
 393  
 394    return ary;
 395  }
 396  
 397  static void *
 398  c_parray(VALUE v, long *size)
 399  {
 400    int i, len;
 401    void **ary;
 402    VALUE e;
 403  
 404    len = RARRAY(v)->len;
 405    *size = sizeof(void*) * len;
 406    ary = dlmalloc(*size);
 407    for( i=0; i < len; i++ ){
 408      e = rb_ary_entry(v, i);
 409      switch( TYPE(e) ){
 410      case T_STRING:
 411        {
 412          char *str, *src;
 413          src = RSTRING(e)->ptr;
 414          str = dlstrdup(src);
 415          ary[i] = (void*)str;
 416        };
 417        break;
 418      case T_NIL:
 419        ary[i] = NULL;
 420        break;
 421      case T_DATA:
 422        if( rb_obj_is_kind_of(e, rb_cDLPtrData) ){
 423          struct ptr_data *pdata;
 424          Data_Get_Struct(e, struct ptr_data, pdata);
 425          ary[i] = (void*)(pdata->ptr);
 426        }
 427        else{
 428          rb_raise(rb_eDLTypeError, "unexpected type of the element #%d", i);
 429        };
 430        break;
 431      default:
 432        rb_raise(rb_eDLTypeError, "unexpected type of the element #%d", i);
 433        break;
 434      };
 435    };
 436  
 437    return ary;
 438  }
 439  
 440  void *
 441  rb_ary2cary(char t, VALUE v, long *size)
 442  {
 443    int len;
 444    VALUE val0;
 445  
 446    if( TYPE(v) != T_ARRAY ){
 447      rb_raise(rb_eDLTypeError, "an array is expected.");
 448    };
 449  
 450    len = RARRAY(v)->len;
 451    if( len == 0 ){
 452      return NULL;
 453    };
 454  
 455    if( !size ){
 456      size = ALLOCA_N(long,1);
 457    };
 458  
 459    val0 = rb_ary_entry(v,0);
 460    switch( TYPE(val0) ){
 461    case T_FIXNUM:
 462    case T_BIGNUM:
 463      switch( t ){
 464      case 'C': case 'c':
 465        return (void*)c_carray(v,size);
 466      case 'H': case 'h':
 467        return (void*)c_harray(v,size);
 468      case 'I': case 'i':
 469        return (void*)c_iarray(v,size);
 470      case 'L': case 'l': case 0:
 471        return (void*)c_larray(v,size);
 472      default:
 473        rb_raise(rb_eDLTypeError, "type mismatch");
 474      };
 475    case T_STRING:
 476      return (void*)c_parray(v,size);
 477    case T_FLOAT:
 478      switch( t ){
 479      case 'F': case 'f':
 480        return (void*)c_farray(v,size);
 481      case 'D': case 'd': case 0:
 482        return (void*)c_darray(v,size);
 483      };
 484      rb_raise(rb_eDLTypeError, "type mismatch");
 485    case T_DATA:
 486      if( rb_obj_is_kind_of(val0, rb_cDLPtrData) ){
 487        return (void*)c_parray(v,size);
 488      };
 489      rb_raise(rb_eDLTypeError, "type mismatch");
 490    default:
 491      rb_raise(rb_eDLTypeError, "unsupported type");
 492    };
 493  }
 494  
 495  VALUE
 496  rb_str_to_ptr(VALUE self)
 497  {
 498    char *ptr;
 499    int  len;
 500  
 501    len = RSTRING(self)->len;
 502    ptr = (char*)dlmalloc(len + 1);
 503    memcpy(ptr, RSTRING(self)->ptr, len);
 504    ptr[len] = '\0';
 505    return rb_dlptr_new((void*)ptr,len,dlfree);
 506  }
 507  
 508  VALUE
 509  rb_ary_to_ptr(int argc, VALUE argv[], VALUE self)
 510  {
 511    void *ptr;
 512    VALUE t;
 513    long size;
 514  
 515    switch( rb_scan_args(argc, argv, "01", &t) ){
 516    case 1:
 517      ptr = rb_ary2cary(StringValuePtr(t)[0], self, &size);
 518      break;
 519    case 0:
 520      ptr = rb_ary2cary(0, self, &size);
 521      break;
 522    };
 523    return ptr ? rb_dlptr_new(ptr, size, dlfree) : Qnil;
 524  }
 525  
 526  VALUE
 527  rb_io_to_ptr(VALUE self)
 528  {
 529    OpenFile *fptr;
 530    FILE     *fp;
 531  
 532    GetOpenFile(self, fptr);
 533    fp = fptr->f;
 534  
 535    return fp ? rb_dlptr_new(fp, sizeof(FILE), 0) : Qnil;
 536  };
 537  
 538  VALUE
 539  rb_dl_dlopen(int argc, VALUE argv[], VALUE self)
 540  {
 541    return rb_class_new_instance(argc, argv, rb_cDLHandle);
 542  }
 543  
 544  VALUE
 545  rb_dl_malloc(VALUE self, VALUE size)
 546  {
 547    return rb_dlptr_malloc(DLNUM2LONG(size), dlfree);
 548  }
 549  
 550  VALUE
 551  rb_dl_strdup(VALUE self, VALUE str)
 552  {
 553    void *p;
 554  
 555    str = rb_String(str);
 556    return rb_dlptr_new(strdup(RSTRING(str)->ptr), RSTRING(str)->len, dlfree);
 557  }
 558  
 559  static VALUE
 560  rb_dl_sizeof(VALUE self, VALUE str)
 561  {
 562    return INT2NUM(dlsizeof(StringValuePtr(str)));
 563  }
 564  
 565  static VALUE
 566  rb_dl_callback(int argc, VALUE argv[], VALUE self)
 567  {
 568    VALUE type, proc;
 569    int rettype, entry, i;
 570    char fname[127];
 571  
 572    proc = Qnil;
 573    switch( rb_scan_args(argc, argv, "11", &type, &proc) ){
 574    case 1:
 575      if( rb_block_given_p() ){
 576        proc = rb_f_lambda();
 577      }
 578      else{
 579        proc = Qnil;
 580      }
 581    default:
 582      break;
 583    }
 584  
 585    Check_Type(type, T_STRING);
 586    switch( RSTRING(type)->ptr[0] ){
 587    case '0':
 588      rettype = 0x00;
 589      break;
 590    case 'C':
 591      rettype = 0x01;
 592      break;
 593    case 'H':
 594      rettype = 0x02;
 595      break;
 596    case 'I':
 597      rettype = 0x03;
 598      break;
 599    case 'L':
 600      rettype = 0x04;
 601      break;
 602    case 'F':
 603      rettype = 0x05;
 604      break;
 605    case 'D':
 606      rettype = 0x06;
 607      break;
 608    case 'P':
 609      rettype = 0x07;
 610      break;
 611    default:
 612      rb_raise(rb_eDLTypeError, "unsupported type `%c'", RSTRING(type)->ptr[0]);
 613    }
 614  
 615    entry = -1;
 616    for( i=0; i < MAX_CALLBACK; i++ ){
 617      if( rb_hash_aref(DLFuncTable, rb_assoc_new(INT2NUM(rettype), INT2NUM(i))) == Qnil ){
 618        entry = i;
 619        break;
 620      }
 621    }
 622    if( entry < 0 ){
 623      rb_raise(rb_eDLError, "too many callbacks are defined.");
 624    }
 625  
 626    rb_hash_aset(DLFuncTable,
 627                 rb_assoc_new(INT2NUM(rettype),INT2NUM(entry)),
 628                 rb_assoc_new(type,proc));
 629    sprintf(fname, "rb_dl_callback_func_%d_%d", rettype, entry);
 630    return rb_dlsym_new((void (*)())rb_dl_callback_table[rettype][entry],
 631                        fname, RSTRING(type)->ptr);
 632  }
 633  
 634  static VALUE
 635  rb_dl_remove_callback(VALUE mod, VALUE sym)
 636  {
 637    freefunc_t f = rb_dlsym2csym(sym);
 638    int i, j;
 639  
 640    for( i=0; i < CALLBACK_TYPES; i++ ){
 641      for( j=0; j < MAX_CALLBACK; j++ ){
 642        if( rb_dl_callback_table[i][j] == f ){
 643          rb_hash_aset(DLFuncTable, rb_assoc_new(INT2NUM(i),INT2NUM(j)),Qnil);
 644          break;
 645        }
 646      }
 647    }
 648    return Qnil;
 649  }
 650  
 651  void
 652  Init_dl()
 653  {
 654    void Init_dlptr();
 655    void Init_dlsym();
 656    void Init_dlhandle();
 657  
 658    id_call = rb_intern("call");
 659  
 660    rb_mDL = rb_define_module("DL");
 661  
 662    rb_eDLError = rb_define_class_under(rb_mDL, "DLError", rb_eStandardError);
 663    rb_eDLTypeError = rb_define_class_under(rb_mDL, "DLTypeError", rb_eDLError);
 664  
 665    DLFuncTable = rb_hash_new();
 666    init_dl_func_table();
 667    rb_define_const(rb_mDL, "FuncTable", DLFuncTable);
 668  
 669    rb_define_const(rb_mDL, "RTLD_GLOBAL", INT2NUM(RTLD_GLOBAL));
 670    rb_define_const(rb_mDL, "RTLD_LAZY",   INT2NUM(RTLD_LAZY));
 671    rb_define_const(rb_mDL, "RTLD_NOW",    INT2NUM(RTLD_NOW));
 672  
 673    rb_define_const(rb_mDL, "ALIGN_INT",   INT2NUM(ALIGN_INT));
 674    rb_define_const(rb_mDL, "ALIGN_LONG",  INT2NUM(ALIGN_LONG));
 675    rb_define_const(rb_mDL, "ALIGN_FLOAT", INT2NUM(ALIGN_FLOAT));
 676    rb_define_const(rb_mDL, "ALIGN_SHORT", INT2NUM(ALIGN_SHORT));
 677    rb_define_const(rb_mDL, "ALIGN_DOUBLE",INT2NUM(ALIGN_DOUBLE));
 678    rb_define_const(rb_mDL, "ALIGN_VOIDP", INT2NUM(ALIGN_VOIDP));
 679  
 680    rb_define_const(rb_mDL, "VERSION",     rb_tainted_str_new2(DL_VERSION));
 681    rb_define_const(rb_mDL, "MAJOR_VERSION", INT2NUM(DL_MAJOR_VERSION));
 682    rb_define_const(rb_mDL, "MINOR_VERSION", INT2NUM(DL_MINOR_VERSION));
 683    rb_define_const(rb_mDL, "PATCH_VERSION", INT2NUM(DL_PATCH_VERSION));
 684    rb_define_const(rb_mDL, "MAX_ARG", INT2NUM(MAX_ARG));
 685    rb_define_const(rb_mDL, "DLSTACK", rb_tainted_str_new2(DLSTACK_METHOD));
 686  
 687    rb_define_module_function(rb_mDL, "dlopen", rb_dl_dlopen, -1);
 688    rb_define_module_function(rb_mDL, "callback", rb_dl_callback, -1);
 689    rb_define_module_function(rb_mDL, "define_callback", rb_dl_callback, -1);
 690    rb_define_module_function(rb_mDL, "remove_callback", rb_dl_remove_callback, 1);
 691    rb_define_module_function(rb_mDL, "malloc", rb_dl_malloc, 1);
 692    rb_define_module_function(rb_mDL, "strdup", rb_dl_strdup, 1);
 693    rb_define_module_function(rb_mDL, "sizeof", rb_dl_sizeof, 1);
 694  
 695    Init_dlptr();
 696    Init_dlsym();
 697    Init_dlhandle();
 698  
 699    rb_define_const(rb_mDL, "FREE", rb_dlsym_new(dlfree, "free", "0P"));
 700  
 701    rb_define_method(rb_cString, "to_ptr", rb_str_to_ptr, 0);
 702    rb_define_method(rb_cArray, "to_ptr", rb_ary_to_ptr, -1);
 703    rb_define_method(rb_cIO, "to_ptr", rb_io_to_ptr, 0);
 704  }