In Files

  • dl/dl.c

DL::Symbol

Public Class Methods

char2type(p1) click to toggle source
 
               VALUE
rb_s_dlsym_char2type(VALUE self, VALUE ch)
{
  const char *type;

  type = char2type(StringValuePtr(ch)[0]);

  if (type == NULL)
    return Qnil;
  else
    return rb_str_new2(type);
}
            
new(p1, p2 = v2, p3 = v3) click to toggle source
 
               VALUE
rb_dlsym_initialize(int argc, VALUE argv[], VALUE self)
{
  VALUE addr, name, type;
  struct sym_data *data;
  void *saddr;
  const char *sname, *stype;

  rb_scan_args(argc, argv, "12", &addr, &name, &type);

  saddr = (void*)(DLNUM2LONG(rb_Integer(addr)));
  if (!NIL_P(name)) StringValue(name);
  stype = NIL_P(type) ? NULL : StringValuePtr(type);
  sname = NIL_P(name) ? NULL : RSTRING(name)->ptr;

  if( saddr ){
    Data_Get_Struct(self, struct sym_data, data);
    if( data->name ) free(data->name);
    if( data->type ) free(data->type);
    data->func = saddr;
    data->name = sname ? strdup(sname) : 0;
    data->type = stype ? strdup(stype) : 0;
    data->len  = stype ? strlen(stype) : 0;
  }

  return Qnil;
}
            

Public Instance Methods

[](*args) click to toggle source

defined(DLSTACK_GUARD)

 
               VALUE
rb_dlsym_call(int argc, VALUE argv[], VALUE self)
{
  struct sym_data *sym;
  ANY_TYPE *args;
  ANY_TYPE *dargs;
  ANY_TYPE ret;
  int   *dtypes;
  VALUE val;
  VALUE dvals;
  int i;
  long ftype;
  void *func;

  rb_secure_update(self);
  Data_Get_Struct(self, struct sym_data, sym);
  DEBUG_CODE({
    printf("rb_dlsym_call(): type = '%s', func = 0x%x\n", sym->type, sym->func);
  });
  if( (sym->len - 1) != argc ){
    rb_raise(rb_eArgError, "%d arguments are needed", sym->len - 1);
  }

  ftype = 0;
  dvals = Qnil;

  args = ALLOC_N(ANY_TYPE, sym->len - 1);
  dargs = ALLOC_N(ANY_TYPE, sym->len - 1);
  dtypes = ALLOC_N(int, sym->len - 1);
#define FREE_ARGS {xfree(args); xfree(dargs); xfree(dtypes);}

  for( i = sym->len - 2; i >= 0; i-- ){
    dtypes[i] = 0;

    switch( sym->type[i+1] ){
    case 'p':
      dtypes[i] = 'p';
    case 'P':
      {
        struct ptr_data *data;
        VALUE pval;

        if( argv[i] == Qnil ){
          ANY2P(args[i]) = DLVOIDP(0);
        }
        else{
          if( rb_obj_is_kind_of(argv[i], rb_cDLPtrData) ){
            pval = argv[i];
          }
          else{
            pval = rb_funcall(argv[i], rb_intern("to_ptr"), 0);
            if( !rb_obj_is_kind_of(pval, rb_cDLPtrData) ){
              rb_raise(rb_eDLTypeError, "unexpected type of argument #%d", i);
            }
          }
          rb_check_safe_obj(pval);
          Data_Get_Struct(pval, struct ptr_data, data);
          ANY2P(args[i]) = DLVOIDP(data->ptr);
        }
      }
      PUSH_P(ftype);
      break;
    case 'a':
      dtypes[i] = 'a';
    case 'A':
      if( argv[i] == Qnil ){
        ANY2P(args[i]) = DLVOIDP(0);
      }
      else{
        ANY2P(args[i]) = DLVOIDP(rb_ary2cary(0, argv[i], NULL));
      }
      PUSH_P(ftype);
      break;
    case 'C':
      ANY2C(args[i]) = DLCHAR(NUM2CHR(argv[i]));
      PUSH_C(ftype);
      break;
    case 'c':
      ANY2C(dargs[i]) = DLCHAR(NUM2CHR(argv[i]));
      ANY2P(args[i]) = DLVOIDP(&(ANY2C(dargs[i])));
      dtypes[i] = 'c';
      PUSH_P(ftype);
      break;
    case 'H':
      ANY2H(args[i]) = DLSHORT(NUM2INT(argv[i]));
      PUSH_C(ftype);
      break;
    case 'h':
      ANY2H(dargs[i]) = DLSHORT(NUM2INT(argv[i]));
      ANY2P(args[i]) = DLVOIDP(&(ANY2H(dargs[i])));
      dtypes[i] = 'h';
      PUSH_P(ftype);
      break;
    case 'I':
      ANY2I(args[i]) = DLINT(NUM2INT(argv[i]));
      PUSH_I(ftype);
      break;
    case 'i':
      ANY2I(dargs[i]) = DLINT(NUM2INT(argv[i]));
      ANY2P(args[i]) = DLVOIDP(&(ANY2I(dargs[i])));
      dtypes[i] = 'i';
      PUSH_P(ftype);
      break;
    case 'L':
      ANY2L(args[i]) = DLNUM2LONG(argv[i]);
      PUSH_L(ftype);
      break;
    case 'l':
      ANY2L(dargs[i]) = DLNUM2LONG(argv[i]);
      ANY2P(args[i]) = DLVOIDP(&(ANY2L(dargs[i])));
      dtypes[i] = 'l';
      PUSH_P(ftype);
      break;
    case 'F':
      Check_Type(argv[i], T_FLOAT);
      ANY2F(args[i]) = DLFLOAT(RFLOAT(argv[i])->value);
      PUSH_F(ftype);
      break;
    case 'f':
      Check_Type(argv[i], T_FLOAT);
      ANY2F(dargs[i]) = DLFLOAT(RFLOAT(argv[i])->value);
      ANY2P(args[i]) = DLVOIDP(&(ANY2F(dargs[i])));
      dtypes[i] = 'f';
      PUSH_P(ftype);
      break;
    case 'D':
      Check_Type(argv[i], T_FLOAT);
      ANY2D(args[i]) = RFLOAT(argv[i])->value;
      PUSH_D(ftype);
      break;
    case 'd':
      Check_Type(argv[i], T_FLOAT);
      ANY2D(dargs[i]) = RFLOAT(argv[i])->value;
      ANY2P(args[i]) = DLVOIDP(&(ANY2D(dargs[i])));
      dtypes[i] = 'd';
      PUSH_P(ftype);
      break;
    case 'S':
      if( argv[i] == Qnil ){
        ANY2S(args[i]) = DLSTR(0);
      }
      else{
        VALUE str = argv[i];
        SafeStringValue(str);
        ANY2S(args[i]) = DLSTR(RSTRING(str)->ptr);
      }
      PUSH_P(ftype);
      break;
    case 's':
      {
        VALUE str = argv[i];
        SafeStringValue(str);
        ANY2S(args[i]) = DLSTR(dlmalloc(RSTRING(str)->len + 1));
        memcpy((char*)(ANY2S(args[i])), RSTRING(str)->ptr, RSTRING(str)->len + 1);
        dtypes[i] = 's';
      }
      PUSH_P(ftype);
      break;
    default:
      FREE_ARGS;
      rb_raise(rb_eDLTypeError,
               "unknown type '%c' of the return value.",
               sym->type[i+1]);
    }
  }

  switch( sym->type[0] ){
  case '0':
    PUSH_0(ftype);
    break;
  case 'P':
  case 'p':
  case 'S':
  case 's':
  case 'A':
  case 'a':
    PUSH_P(ftype);
    break;
  case 'C':
  case 'c':
    PUSH_C(ftype);
    break;
  case 'H':
  case 'h':
    PUSH_H(ftype);
    break;
  case 'I':
  case 'i':
    PUSH_I(ftype);
    break;
  case 'L':
  case 'l':
    PUSH_L(ftype);
    break;
  case 'F':
  case 'f':
    PUSH_F(ftype);
    break;
  case 'D':
  case 'd':
    PUSH_D(ftype);
    break;
  default:
    FREE_ARGS;
    rb_raise(rb_eDLTypeError,
             "unknown type `%c' of the return value.",
             sym->type[0]);
  }

  func = sym->func;

#if defined(DLSTACK)
  {
#if defined(DLSTACK_SIZE)
  int  stk_size;
  long stack[DLSTACK_SIZE];
  long *sp;

  sp = stack;
  stk_size = stack_size(sym);
  if( stk_size < 0 ){
    FREE_ARGS;
    rb_raise(rb_eDLTypeError, "unknown type '%c'.", -stk_size);
  }
  else if( stk_size > (int)(DLSTACK_SIZE) ){
    FREE_ARGS;
    rb_raise(rb_eArgError, "too many arguments.");
  }
#endif

  DLSTACK_START(sym);

#if defined(DLSTACK_REVERSE)
  for( i = sym->len - 2; i >= 0; i-- )
#else
  for( i = 0; i <= sym->len -2; i++ )
#endif
  {
    switch( sym->type[i+1] ){
    case 'p':
    case 'P':
      DLSTACK_PUSH_P(ANY2P(args[i]));
      break;
    case 'a':
    case 'A':
      DLSTACK_PUSH_P(ANY2P(args[i]));
      break;
    case 'C':
      DLSTACK_PUSH_C(ANY2C(args[i]));
      break;
    case 'c':
      DLSTACK_PUSH_P(ANY2P(args[i]));
      break;
    case 'H':
      DLSTACK_PUSH_H(ANY2H(args[i]));
      break;
    case 'h':
      DLSTACK_PUSH_P(ANY2P(args[i]));
      break;
    case 'I':
      DLSTACK_PUSH_I(ANY2I(args[i]));
      break;
    case 'i':
      DLSTACK_PUSH_P(ANY2P(args[i]));
      break;
    case 'L':
      DLSTACK_PUSH_L(ANY2L(args[i]));
      break;
    case 'l':
      DLSTACK_PUSH_P(ANY2P(args[i]));
      break;
    case 'F':
      DLSTACK_PUSH_F(ANY2F(args[i]));
      break;
    case 'f':
      DLSTACK_PUSH_P(ANY2P(args[i]));
      break;
    case 'D':
      DLSTACK_PUSH_D(ANY2D(args[i]));
      break;
    case 'd':
      DLSTACK_PUSH_P(ANY2P(args[i]));
      break;
    case 'S':
    case 's':
      DLSTACK_PUSH_P(ANY2S(args[i]));
      break;
    }
  }
  DLSTACK_END(sym->type);

#ifdef DLSTACK_GUARD
  if(!rb_dlsym_guardcall(sym->type[0], &ret, stack, func)) {
    FREE_ARGS;
    rb_raise(rb_eDLTypeError, "unknown type `%c'", sym->type[0]);
  }
#else /* defined(DLSTACK_GUARD) */
  {
    switch( sym->type[0] ){
    case '0':
      {
        void (*f)(DLSTACK_PROTO) = func;
        f(DLSTACK_ARGS);
      }
      break;
    case 'P':
    case 'p':
      {
        void * (*f)(DLSTACK_PROTO) = func;
        ret.p = f(DLSTACK_ARGS);
      }
      break;
    case 'C':
    case 'c':
      {
        char (*f)(DLSTACK_PROTO) = func;
        ret.c = f(DLSTACK_ARGS);
      }
      break;
    case 'H':
    case 'h':
      {
        short (*f)(DLSTACK_PROTO) = func;
        ret.h = f(DLSTACK_ARGS);
      }
      break;
    case 'I':
    case 'i':
      {
        int (*f)(DLSTACK_PROTO) = func;
        ret.i = f(DLSTACK_ARGS);
      }
      break;
    case 'L':
    case 'l':
      {
        long (*f)(DLSTACK_PROTO) = func;
        ret.l = f(DLSTACK_ARGS);
      }
      break;
    case 'F':
    case 'f':
      {
        float (*f)(DLSTACK_PROTO) = func;
        ret.f = f(DLSTACK_ARGS);
      }
      break;
    case 'D':
    case 'd':
      {
        double (*f)(DLSTACK_PROTO) = func;
        ret.d = f(DLSTACK_ARGS);
      }
      break;
    case 'S':
    case 's':
      {
        char * (*f)(DLSTACK_PROTO) = func;
        ret.s = f(DLSTACK_ARGS);
      }
      break;
    default:
      FREE_ARGS;
      rb_raise(rb_eDLTypeError, "unknown type `%c'", sym->type[0]);
    }
  }
#endif /* defubed(DLSTACK_GUARD) */

  {
    /*
     * We should get the value of errno/GetLastError() before calling another functions.
     */
    int last_errno = errno;
#ifdef _WIN32
    DWORD win32_last_err = GetLastError();
#endif

    rb_thread_local_aset(rb_thread_current(), rb_dl_id_DLErrno, INT2NUM(last_errno));
#ifdef _WIN32
    rb_thread_local_aset(rb_thread_current(), rb_dl_id_DLW32Error, INT2NUM(win32_last_err));
#endif
  }

  }
#else /* defined(DLSTACK) */
  switch(ftype){
#include "call.func"
  default:
    FREE_ARGS;
    rb_raise(rb_eDLTypeError, "unsupported function type `%s'", sym->type);
  }
#endif /* defined(DLSTACK) */

  switch( sym->type[0] ){
  case '0':
    val = Qnil;
    break;
  case 'P':
    val = rb_dlptr_new((void*)(ANY2P(ret)), 0, 0);
    break;
  case 'p':
    val = rb_dlptr_new((void*)(ANY2P(ret)), 0, dlfree);
    break;
  case 'C':
  case 'c':
    val = CHR2FIX((char)(ANY2C(ret)));
    break;
  case 'H':
  case 'h':
    val = INT2NUM((short)(ANY2H(ret)));
    break;
  case 'I':
  case 'i':
    val = INT2NUM((int)(ANY2I(ret)));
    break;
  case 'L':
  case 'l':
    val = DLLONG2NUM((long)(ANY2L(ret)));
    break;
  case 'F':
  case 'f':
    val = rb_float_new((double)(ANY2F(ret)));
    break;
  case 'D':
  case 'd':
    val = rb_float_new((double)(ANY2D(ret)));
    break;
  case 'S':
    if( ANY2S(ret) ){
      val = rb_tainted_str_new2((char*)(ANY2S(ret)));
    }
    else{
      val = Qnil;
    }
    break;
  case 's':
    if( ANY2S(ret) ){
      val = rb_tainted_str_new2((char*)(ANY2S(ret)));
      DEBUG_CODE({
        printf("dlfree(%s)\n",(char*)(ANY2S(ret)));
      });
      dlfree((void*)(ANY2S(ret)));
    }
    else{
      val = Qnil;
    }
    break;
  default:
    FREE_ARGS;
    rb_raise(rb_eDLTypeError, "unknown type `%c'", sym->type[0]);
  }

  dvals = rb_ary_new();
  for( i = 0; i <= sym->len - 2; i++ ){
    if( dtypes[i] ){
      switch( dtypes[i] ){
      case 'c':
        rb_ary_push(dvals, CHR2FIX(*((char*)(ANY2P(args[i])))));
        break;
      case 'h':
        rb_ary_push(dvals, INT2NUM(*((short*)(ANY2P(args[i])))));
        break;
      case 'i':
        rb_ary_push(dvals, INT2NUM(*((int*)(ANY2P(args[i])))));
        break;
      case 'l':
        rb_ary_push(dvals, DLLONG2NUM(*((long*)(ANY2P(args[i])))));
        break;
      case 'f':
        rb_ary_push(dvals, rb_float_new(*((float*)(ANY2P(args[i])))));
        break;
      case 'd':
        rb_ary_push(dvals, rb_float_new(*((double*)(ANY2P(args[i])))));
        break;
      case 'p':
        rb_ary_push(dvals, rb_dlptr_new((void*)(ANY2P(args[i])), 0, 0));
        break;
      case 'a':
        rb_ary_push(dvals, rb_dlptr_new((void*)ANY2P(args[i]), 0, 0));
        break;
      case 's':
        rb_ary_push(dvals, rb_tainted_str_new2((char*)ANY2S(args[i])));
        DEBUG_CODE({
          printf("dlfree(%s)\n",(char*)ANY2S(args[i]));
        });
        dlfree((void*)ANY2S(args[i]));
        break;
      default:
        {
          char c = dtypes[i];
          FREE_ARGS;
          rb_raise(rb_eRuntimeError, "unknown argument type '%c'", i, c);
        }
      }
    }
    else{
      switch( sym->type[i+1] ){
      case 'A':
        dlfree((void*)ANY2P(args[i]));
        break;
      }
      rb_ary_push(dvals, argv[i]);
    }
  }

  FREE_ARGS;
#undef FREE_ARGS
  return rb_assoc_new(val,dvals);
}
            
call(*args) click to toggle source

defined(DLSTACK_GUARD)

 
               VALUE
rb_dlsym_call(int argc, VALUE argv[], VALUE self)
{
  struct sym_data *sym;
  ANY_TYPE *args;
  ANY_TYPE *dargs;
  ANY_TYPE ret;
  int   *dtypes;
  VALUE val;
  VALUE dvals;
  int i;
  long ftype;
  void *func;

  rb_secure_update(self);
  Data_Get_Struct(self, struct sym_data, sym);
  DEBUG_CODE({
    printf("rb_dlsym_call(): type = '%s', func = 0x%x\n", sym->type, sym->func);
  });
  if( (sym->len - 1) != argc ){
    rb_raise(rb_eArgError, "%d arguments are needed", sym->len - 1);
  }

  ftype = 0;
  dvals = Qnil;

  args = ALLOC_N(ANY_TYPE, sym->len - 1);
  dargs = ALLOC_N(ANY_TYPE, sym->len - 1);
  dtypes = ALLOC_N(int, sym->len - 1);
#define FREE_ARGS {xfree(args); xfree(dargs); xfree(dtypes);}

  for( i = sym->len - 2; i >= 0; i-- ){
    dtypes[i] = 0;

    switch( sym->type[i+1] ){
    case 'p':
      dtypes[i] = 'p';
    case 'P':
      {
        struct ptr_data *data;
        VALUE pval;

        if( argv[i] == Qnil ){
          ANY2P(args[i]) = DLVOIDP(0);
        }
        else{
          if( rb_obj_is_kind_of(argv[i], rb_cDLPtrData) ){
            pval = argv[i];
          }
          else{
            pval = rb_funcall(argv[i], rb_intern("to_ptr"), 0);
            if( !rb_obj_is_kind_of(pval, rb_cDLPtrData) ){
              rb_raise(rb_eDLTypeError, "unexpected type of argument #%d", i);
            }
          }
          rb_check_safe_obj(pval);
          Data_Get_Struct(pval, struct ptr_data, data);
          ANY2P(args[i]) = DLVOIDP(data->ptr);
        }
      }
      PUSH_P(ftype);
      break;
    case 'a':
      dtypes[i] = 'a';
    case 'A':
      if( argv[i] == Qnil ){
        ANY2P(args[i]) = DLVOIDP(0);
      }
      else{
        ANY2P(args[i]) = DLVOIDP(rb_ary2cary(0, argv[i], NULL));
      }
      PUSH_P(ftype);
      break;
    case 'C':
      ANY2C(args[i]) = DLCHAR(NUM2CHR(argv[i]));
      PUSH_C(ftype);
      break;
    case 'c':
      ANY2C(dargs[i]) = DLCHAR(NUM2CHR(argv[i]));
      ANY2P(args[i]) = DLVOIDP(&(ANY2C(dargs[i])));
      dtypes[i] = 'c';
      PUSH_P(ftype);
      break;
    case 'H':
      ANY2H(args[i]) = DLSHORT(NUM2INT(argv[i]));
      PUSH_C(ftype);
      break;
    case 'h':
      ANY2H(dargs[i]) = DLSHORT(NUM2INT(argv[i]));
      ANY2P(args[i]) = DLVOIDP(&(ANY2H(dargs[i])));
      dtypes[i] = 'h';
      PUSH_P(ftype);
      break;
    case 'I':
      ANY2I(args[i]) = DLINT(NUM2INT(argv[i]));
      PUSH_I(ftype);
      break;
    case 'i':
      ANY2I(dargs[i]) = DLINT(NUM2INT(argv[i]));
      ANY2P(args[i]) = DLVOIDP(&(ANY2I(dargs[i])));
      dtypes[i] = 'i';
      PUSH_P(ftype);
      break;
    case 'L':
      ANY2L(args[i]) = DLNUM2LONG(argv[i]);
      PUSH_L(ftype);
      break;
    case 'l':
      ANY2L(dargs[i]) = DLNUM2LONG(argv[i]);
      ANY2P(args[i]) = DLVOIDP(&(ANY2L(dargs[i])));
      dtypes[i] = 'l';
      PUSH_P(ftype);
      break;
    case 'F':
      Check_Type(argv[i], T_FLOAT);
      ANY2F(args[i]) = DLFLOAT(RFLOAT(argv[i])->value);
      PUSH_F(ftype);
      break;
    case 'f':
      Check_Type(argv[i], T_FLOAT);
      ANY2F(dargs[i]) = DLFLOAT(RFLOAT(argv[i])->value);
      ANY2P(args[i]) = DLVOIDP(&(ANY2F(dargs[i])));
      dtypes[i] = 'f';
      PUSH_P(ftype);
      break;
    case 'D':
      Check_Type(argv[i], T_FLOAT);
      ANY2D(args[i]) = RFLOAT(argv[i])->value;
      PUSH_D(ftype);
      break;
    case 'd':
      Check_Type(argv[i], T_FLOAT);
      ANY2D(dargs[i]) = RFLOAT(argv[i])->value;
      ANY2P(args[i]) = DLVOIDP(&(ANY2D(dargs[i])));
      dtypes[i] = 'd';
      PUSH_P(ftype);
      break;
    case 'S':
      if( argv[i] == Qnil ){
        ANY2S(args[i]) = DLSTR(0);
      }
      else{
        VALUE str = argv[i];
        SafeStringValue(str);
        ANY2S(args[i]) = DLSTR(RSTRING(str)->ptr);
      }
      PUSH_P(ftype);
      break;
    case 's':
      {
        VALUE str = argv[i];
        SafeStringValue(str);
        ANY2S(args[i]) = DLSTR(dlmalloc(RSTRING(str)->len + 1));
        memcpy((char*)(ANY2S(args[i])), RSTRING(str)->ptr, RSTRING(str)->len + 1);
        dtypes[i] = 's';
      }
      PUSH_P(ftype);
      break;
    default:
      FREE_ARGS;
      rb_raise(rb_eDLTypeError,
               "unknown type '%c' of the return value.",
               sym->type[i+1]);
    }
  }

  switch( sym->type[0] ){
  case '0':
    PUSH_0(ftype);
    break;
  case 'P':
  case 'p':
  case 'S':
  case 's':
  case 'A':
  case 'a':
    PUSH_P(ftype);
    break;
  case 'C':
  case 'c':
    PUSH_C(ftype);
    break;
  case 'H':
  case 'h':
    PUSH_H(ftype);
    break;
  case 'I':
  case 'i':
    PUSH_I(ftype);
    break;
  case 'L':
  case 'l':
    PUSH_L(ftype);
    break;
  case 'F':
  case 'f':
    PUSH_F(ftype);
    break;
  case 'D':
  case 'd':
    PUSH_D(ftype);
    break;
  default:
    FREE_ARGS;
    rb_raise(rb_eDLTypeError,
             "unknown type `%c' of the return value.",
             sym->type[0]);
  }

  func = sym->func;

#if defined(DLSTACK)
  {
#if defined(DLSTACK_SIZE)
  int  stk_size;
  long stack[DLSTACK_SIZE];
  long *sp;

  sp = stack;
  stk_size = stack_size(sym);
  if( stk_size < 0 ){
    FREE_ARGS;
    rb_raise(rb_eDLTypeError, "unknown type '%c'.", -stk_size);
  }
  else if( stk_size > (int)(DLSTACK_SIZE) ){
    FREE_ARGS;
    rb_raise(rb_eArgError, "too many arguments.");
  }
#endif

  DLSTACK_START(sym);

#if defined(DLSTACK_REVERSE)
  for( i = sym->len - 2; i >= 0; i-- )
#else
  for( i = 0; i <= sym->len -2; i++ )
#endif
  {
    switch( sym->type[i+1] ){
    case 'p':
    case 'P':
      DLSTACK_PUSH_P(ANY2P(args[i]));
      break;
    case 'a':
    case 'A':
      DLSTACK_PUSH_P(ANY2P(args[i]));
      break;
    case 'C':
      DLSTACK_PUSH_C(ANY2C(args[i]));
      break;
    case 'c':
      DLSTACK_PUSH_P(ANY2P(args[i]));
      break;
    case 'H':
      DLSTACK_PUSH_H(ANY2H(args[i]));
      break;
    case 'h':
      DLSTACK_PUSH_P(ANY2P(args[i]));
      break;
    case 'I':
      DLSTACK_PUSH_I(ANY2I(args[i]));
      break;
    case 'i':
      DLSTACK_PUSH_P(ANY2P(args[i]));
      break;
    case 'L':
      DLSTACK_PUSH_L(ANY2L(args[i]));
      break;
    case 'l':
      DLSTACK_PUSH_P(ANY2P(args[i]));
      break;
    case 'F':
      DLSTACK_PUSH_F(ANY2F(args[i]));
      break;
    case 'f':
      DLSTACK_PUSH_P(ANY2P(args[i]));
      break;
    case 'D':
      DLSTACK_PUSH_D(ANY2D(args[i]));
      break;
    case 'd':
      DLSTACK_PUSH_P(ANY2P(args[i]));
      break;
    case 'S':
    case 's':
      DLSTACK_PUSH_P(ANY2S(args[i]));
      break;
    }
  }
  DLSTACK_END(sym->type);

#ifdef DLSTACK_GUARD
  if(!rb_dlsym_guardcall(sym->type[0], &ret, stack, func)) {
    FREE_ARGS;
    rb_raise(rb_eDLTypeError, "unknown type `%c'", sym->type[0]);
  }
#else /* defined(DLSTACK_GUARD) */
  {
    switch( sym->type[0] ){
    case '0':
      {
        void (*f)(DLSTACK_PROTO) = func;
        f(DLSTACK_ARGS);
      }
      break;
    case 'P':
    case 'p':
      {
        void * (*f)(DLSTACK_PROTO) = func;
        ret.p = f(DLSTACK_ARGS);
      }
      break;
    case 'C':
    case 'c':
      {
        char (*f)(DLSTACK_PROTO) = func;
        ret.c = f(DLSTACK_ARGS);
      }
      break;
    case 'H':
    case 'h':
      {
        short (*f)(DLSTACK_PROTO) = func;
        ret.h = f(DLSTACK_ARGS);
      }
      break;
    case 'I':
    case 'i':
      {
        int (*f)(DLSTACK_PROTO) = func;
        ret.i = f(DLSTACK_ARGS);
      }
      break;
    case 'L':
    case 'l':
      {
        long (*f)(DLSTACK_PROTO) = func;
        ret.l = f(DLSTACK_ARGS);
      }
      break;
    case 'F':
    case 'f':
      {
        float (*f)(DLSTACK_PROTO) = func;
        ret.f = f(DLSTACK_ARGS);
      }
      break;
    case 'D':
    case 'd':
      {
        double (*f)(DLSTACK_PROTO) = func;
        ret.d = f(DLSTACK_ARGS);
      }
      break;
    case 'S':
    case 's':
      {
        char * (*f)(DLSTACK_PROTO) = func;
        ret.s = f(DLSTACK_ARGS);
      }
      break;
    default:
      FREE_ARGS;
      rb_raise(rb_eDLTypeError, "unknown type `%c'", sym->type[0]);
    }
  }
#endif /* defubed(DLSTACK_GUARD) */

  {
    /*
     * We should get the value of errno/GetLastError() before calling another functions.
     */
    int last_errno = errno;
#ifdef _WIN32
    DWORD win32_last_err = GetLastError();
#endif

    rb_thread_local_aset(rb_thread_current(), rb_dl_id_DLErrno, INT2NUM(last_errno));
#ifdef _WIN32
    rb_thread_local_aset(rb_thread_current(), rb_dl_id_DLW32Error, INT2NUM(win32_last_err));
#endif
  }

  }
#else /* defined(DLSTACK) */
  switch(ftype){
#include "call.func"
  default:
    FREE_ARGS;
    rb_raise(rb_eDLTypeError, "unsupported function type `%s'", sym->type);
  }
#endif /* defined(DLSTACK) */

  switch( sym->type[0] ){
  case '0':
    val = Qnil;
    break;
  case 'P':
    val = rb_dlptr_new((void*)(ANY2P(ret)), 0, 0);
    break;
  case 'p':
    val = rb_dlptr_new((void*)(ANY2P(ret)), 0, dlfree);
    break;
  case 'C':
  case 'c':
    val = CHR2FIX((char)(ANY2C(ret)));
    break;
  case 'H':
  case 'h':
    val = INT2NUM((short)(ANY2H(ret)));
    break;
  case 'I':
  case 'i':
    val = INT2NUM((int)(ANY2I(ret)));
    break;
  case 'L':
  case 'l':
    val = DLLONG2NUM((long)(ANY2L(ret)));
    break;
  case 'F':
  case 'f':
    val = rb_float_new((double)(ANY2F(ret)));
    break;
  case 'D':
  case 'd':
    val = rb_float_new((double)(ANY2D(ret)));
    break;
  case 'S':
    if( ANY2S(ret) ){
      val = rb_tainted_str_new2((char*)(ANY2S(ret)));
    }
    else{
      val = Qnil;
    }
    break;
  case 's':
    if( ANY2S(ret) ){
      val = rb_tainted_str_new2((char*)(ANY2S(ret)));
      DEBUG_CODE({
        printf("dlfree(%s)\n",(char*)(ANY2S(ret)));
      });
      dlfree((void*)(ANY2S(ret)));
    }
    else{
      val = Qnil;
    }
    break;
  default:
    FREE_ARGS;
    rb_raise(rb_eDLTypeError, "unknown type `%c'", sym->type[0]);
  }

  dvals = rb_ary_new();
  for( i = 0; i <= sym->len - 2; i++ ){
    if( dtypes[i] ){
      switch( dtypes[i] ){
      case 'c':
        rb_ary_push(dvals, CHR2FIX(*((char*)(ANY2P(args[i])))));
        break;
      case 'h':
        rb_ary_push(dvals, INT2NUM(*((short*)(ANY2P(args[i])))));
        break;
      case 'i':
        rb_ary_push(dvals, INT2NUM(*((int*)(ANY2P(args[i])))));
        break;
      case 'l':
        rb_ary_push(dvals, DLLONG2NUM(*((long*)(ANY2P(args[i])))));
        break;
      case 'f':
        rb_ary_push(dvals, rb_float_new(*((float*)(ANY2P(args[i])))));
        break;
      case 'd':
        rb_ary_push(dvals, rb_float_new(*((double*)(ANY2P(args[i])))));
        break;
      case 'p':
        rb_ary_push(dvals, rb_dlptr_new((void*)(ANY2P(args[i])), 0, 0));
        break;
      case 'a':
        rb_ary_push(dvals, rb_dlptr_new((void*)ANY2P(args[i]), 0, 0));
        break;
      case 's':
        rb_ary_push(dvals, rb_tainted_str_new2((char*)ANY2S(args[i])));
        DEBUG_CODE({
          printf("dlfree(%s)\n",(char*)ANY2S(args[i]));
        });
        dlfree((void*)ANY2S(args[i]));
        break;
      default:
        {
          char c = dtypes[i];
          FREE_ARGS;
          rb_raise(rb_eRuntimeError, "unknown argument type '%c'", i, c);
        }
      }
    }
    else{
      switch( sym->type[i+1] ){
      case 'A':
        dlfree((void*)ANY2P(args[i]));
        break;
      }
      rb_ary_push(dvals, argv[i]);
    }
  }

  FREE_ARGS;
#undef FREE_ARGS
  return rb_assoc_new(val,dvals);
}
            
cproto() click to toggle source
 
               VALUE
rb_dlsym_cproto(VALUE self)
{
  struct sym_data *sym;
  const char *ptype, *typestr;
  size_t len;
  VALUE val;

  Data_Get_Struct(self, struct sym_data, sym);

  ptype = sym->type;

  if( ptype ){
    typestr = char2type(*ptype++);
    len = strlen(typestr);
    
    val = rb_tainted_str_new(typestr, len);
    if (typestr[len - 1] != '*')
      rb_str_cat(val, " ", 1);

    if( sym->name ){
      rb_str_cat2(val, sym->name);
    }
    else{
      rb_str_cat2(val, "(null)");
    }
    rb_str_cat(val, "(", 1);
    
    while (*ptype) {
      const char *ty = char2type(*ptype++);
      rb_str_cat2(val, ty);
      if (*ptype)
        rb_str_cat(val, ", ", 2);
    }

    rb_str_cat(val, ");", 2);
  }
  else{
    val = rb_tainted_str_new2("void (");
    if( sym->name ){
      rb_str_cat2(val, sym->name);
    }
    else{
      rb_str_cat2(val, "(null)");
    }
    rb_str_cat2(val, ")()");
  }

  return val;
}
            
inspect() click to toggle source
 
               VALUE
rb_dlsym_inspect(VALUE self)
{
  VALUE proto;
  VALUE val;
  char  *str;
  int str_size;
  struct sym_data *sym;

  Data_Get_Struct(self, struct sym_data, sym);
  proto = rb_dlsym_cproto(self);

  str_size = RSTRING(proto)->len + 100;
  str = dlmalloc(str_size);
  snprintf(str, str_size - 1,
          "#<DL::Symbol:0x%lx func=0x%lx '%s'>",
           sym, sym->func, RSTRING(proto)->ptr);
  val = rb_tainted_str_new2(str);
  dlfree(str);

  return val;
}
            
name() click to toggle source
 
               VALUE
rb_dlsym_name(VALUE self)
{
  struct sym_data *sym;

  Data_Get_Struct(self, struct sym_data, sym);
  return sym->name ? rb_tainted_str_new2(sym->name) : Qnil;
}
            
proto() click to toggle source
 
               VALUE
rb_dlsym_proto(VALUE self)
{
  struct sym_data *sym;

  Data_Get_Struct(self, struct sym_data, sym);
  return sym->type ? rb_tainted_str_new2(sym->type) : Qnil;
}
            
to_i() click to toggle source
 
               VALUE
rb_dlsym_to_i(VALUE self)
{
  struct sym_data *sym;

  Data_Get_Struct(self, struct sym_data, sym);
  return DLLONG2NUM(sym);
}
            
to_ptr() click to toggle source
 
               VALUE
rb_dlsym_to_ptr(VALUE self)
{
  struct sym_data *sym;

  Data_Get_Struct(self, struct sym_data, sym);
  return rb_dlptr_new(sym->func, sizeof(freefunc_t), 0);
}
            
to_s() click to toggle source
 
               VALUE
rb_dlsym_cproto(VALUE self)
{
  struct sym_data *sym;
  const char *ptype, *typestr;
  size_t len;
  VALUE val;

  Data_Get_Struct(self, struct sym_data, sym);

  ptype = sym->type;

  if( ptype ){
    typestr = char2type(*ptype++);
    len = strlen(typestr);
    
    val = rb_tainted_str_new(typestr, len);
    if (typestr[len - 1] != '*')
      rb_str_cat(val, " ", 1);

    if( sym->name ){
      rb_str_cat2(val, sym->name);
    }
    else{
      rb_str_cat2(val, "(null)");
    }
    rb_str_cat(val, "(", 1);
    
    while (*ptype) {
      const char *ty = char2type(*ptype++);
      rb_str_cat2(val, ty);
      if (*ptype)
        rb_str_cat(val, ", ", 2);
    }

    rb_str_cat(val, ");", 2);
  }
  else{
    val = rb_tainted_str_new2("void (");
    if( sym->name ){
      rb_str_cat2(val, sym->name);
    }
    else{
      rb_str_cat2(val, "(null)");
    }
    rb_str_cat2(val, ")()");
  }

  return val;
}