在Swig中,如何处理应该更新字符串内容的函数?

时间:2014-02-08 22:58:30

标签: c ruby swig

我正在使用swig生成一些从c到ruby的包装器。

一些函数希望我传入一个将更新的char *。

例如:

void setvarc(int arg1, char * arg2);

我认为在将与函数接口的ruby类中,我可以使用String.new来创建一个足以容纳数据的字符串,然后将其传递给函数。

这样的事情:

return_string = " " * 10
setvarc(arg1, return_string)

但这不是一个非常好的解决方案,并且非常像非红宝石。

我在swig手册的第9章中看到如何使用类型映射来处理参数但不分配空间。 我想我需要围绕这个函数创建一个小的c包装并分配空间,但是我必须在返回后清理它。 Swig似乎也有一些可以处理的类型图,但这并不是一个很好的例子来说明这一点。

这似乎是经常出现的事情。

我认为它应该是这样的。
(我的c生锈了所以这可能是错的,但你明白了)

char * get_value(int arg1) {
   char * buffer = malloc(some_number);
   setvarc(arg1,buffer);
   return buffer
}

然后是一些swig类型图,希望能让ruby获取新字符串的副本并释放空间。

有没有人有一个如何将这一切联系在一起的例子?

2 个答案:

答案 0 :(得分:1)

你应该能够逃脱:

%ignore setvarc;

%newobject get_value;  

%inline %{
    char* get_value(int argc)
    {
       char * buffer = malloc(some_number);
       setvarc(arg1,buffer);
       return buffer;
    }
%}

SWIG应将get_value包装为Ruby字符串,并取得函数分配的内存的所有权(因为%newobject)。

答案 1 :(得分:0)

更新:虽然这很好用但接受的答案有点清洁

我想通了,如果有人需要它,这是一个例子:

/* set a type map for the next set of functions */
/* it just needs to match any arg so it will get triggered */

%typemap(freearg) char {
  free(result);
}

/* create a simple interface that will allocate the required space */
char *get_value(FACREF *facref, char mode);
%inline %{
char *get_value(FACREF *facref, char mode) {
   int fac_size = facref->length + 1;
   char *result = (char *) malloc((sizeof(char) * fac_size) + 1);
   setvarc(facref, result, mode);
   return result;
}
%}

/* clear the typemap when done */
%typemap(in) char;

然后swig用这段代码包装。

SWIGINTERN VALUE
_wrap_get_value(int argc, VALUE *argv, VALUE self) {
  FACREF *arg1 = (FACREF *) 0 ;
  char arg2 ;
  void *argp1 = 0 ;
  int res1 = 0 ;
  char val2 ;
  int ecode2 = 0 ;
  char *result = 0 ;
  VALUE vresult = Qnil;

  if ((argc < 2) || (argc > 2)) {
    rb_raise(rb_eArgError, "wrong # of arguments(%d for 2)",argc); SWIG_fail;
  }
  res1 = SWIG_ConvertPtr(argv[0], &argp1,SWIGTYPE_p_facref, 0 |  0 );
  if (!SWIG_IsOK(res1)) {
    SWIG_exception_fail(SWIG_ArgError(res1), Ruby_Format_TypeError( "", "FACREF *","get_value", 1, argv[0] )); 
  }
  arg1 = (FACREF *)(argp1);
  ecode2 = SWIG_AsVal_char(argv[1], &val2);
  if (!SWIG_IsOK(ecode2)) {
    SWIG_exception_fail(SWIG_ArgError(ecode2), Ruby_Format_TypeError( "", "char","get_value", 2, argv[1] ));
  } 
  arg2 = (char)(val2);
  result = (char *)get_value(arg1,arg2);
  vresult = SWIG_FromCharPtr((const char *)result);
  {
    free(result);
  }
  return vresult;
fail:
  {
    free(result);
  }
  return Qnil;
}