Code cleanup

This commit is contained in:
Pierre Pronchery 2014-04-17 02:30:57 +02:00
parent 83fb382a14
commit a8d343f3bb
2 changed files with 0 additions and 899 deletions

View File

@ -420,389 +420,6 @@ int appinterface_get_args_count(AppInterface * appinterface, size_t * count,
/* useful */
/* appinterface_call
* PRE
* POST
* <= 0 an error occured
* else the number of bytes added to the buffer */
static int _send_bytes(char const * data, size_t datalen, char * buf,
size_t buflen, size_t * pos);
static int _send_string(char const * string, char * buf, size_t buflen,
size_t * pos);
int appinterface_call(AppInterface * appinterface, char buf[], size_t buflen,
char const * function, void ** args, va_list arg)
{
AppInterfaceCall * aic;
size_t pos = 0;
size_t i;
void * p = NULL;
size_t size;
double d;
float f;
int8_t i8;
int16_t i16;
int32_t i32;
int64_t i64;
Buffer * b = NULL;
#ifdef DEBUG
fprintf(stderr, "%s%s%s", "DEBUG: call \"", function, "\"\n");
#endif
if((aic = _appinterface_get_call(appinterface, function)) == NULL
|| _send_string(function, buf, buflen, &pos) != 0)
return -1;
for(i = 0; i < aic->args_cnt; i++)
{
#ifdef DEBUG
fprintf(stderr, "%s%lu%s", "DEBUG: argument ",
(unsigned long)i, "\n");
#endif
size = 0;
if(aic->args[i].direction == AICD_IN)
{
size = aic->args[i].size;
switch(aic->args[i].type)
{
case AICT_VOID:
break;
case AICT_BOOL:
case AICT_INT8:
case AICT_UINT8:
i8 = va_arg(arg, int);
p = &i8;
break;
case AICT_INT16:
case AICT_UINT16:
i16 = htons(va_arg(arg, int));
p = &i16;
break;
case AICT_INT32:
case AICT_UINT32:
i32 = htonl(va_arg(arg, int32_t));
p = &i32;
break;
case AICT_DOUBLE:
d = va_arg(arg, double);
p = &d;
break;
case AICT_FLOAT:
f = va_arg(arg, double);
p = &f;
break;
case AICT_INT64: /* FIXME wrong endian */
case AICT_UINT64:
i64 = va_arg(arg, int64_t);
p = &i64;
break;
case AICT_STRING: /* FIXME handle NULL? */
p = va_arg(arg, String *);
size = strlen(p) + 1;
break;
case AICT_BUFFER: /* FIXME handle NULL? */
b = va_arg(arg, Buffer *);
i32 = htonl(buffer_get_size(b));
p = &i32;
if(_send_bytes(p, sizeof(i32), buf,
buflen, &pos)
!= 0)
return -1;
size = buffer_get_size(b);
p = buffer_get_data(b);
break;
}
}
else if(aic->args[i].direction == AICD_IN_OUT)
{
size = aic->args[i].size;
switch(aic->args[i].type)
{
case AICT_VOID:
break;
case AICT_BOOL:
case AICT_INT8:
case AICT_UINT8:
args[i] = va_arg(arg, int8_t *);
i8 = *(int8_t *)args[i];
p = &i8;
break;
case AICT_INT16:
case AICT_UINT16:
args[i] = va_arg(arg, int16_t *);
i16 = htons(*(int16_t *)args[i]);
p = &i16;
break;
case AICT_INT32:
case AICT_UINT32:
case AICT_FLOAT:
args[i] = va_arg(arg, int32_t *);
i32 = htonl(*(int32_t *)args[i]);
p = &i32;
break;
case AICT_INT64: /* FIXME wrong endian */
case AICT_UINT64:
case AICT_DOUBLE:
args[i] = va_arg(arg, int64_t *);
i64 = *(int64_t *)args[i];
p = &i64;
break;
case AICT_STRING: /* FIXME handle NULL? */
args[i] = va_arg(arg, String **);
p = *(char **)args[i];
size = strlen(p) + 1;
break;
case AICT_BUFFER:
b = va_arg(arg, Buffer *);
args[i] = b;
i32 = htonl(buffer_get_size(b));
p = &i32;
if(_send_bytes(p, sizeof(i32), buf,
buflen, &pos)
!= 0)
return -1;
size = buffer_get_size(b);
p = buffer_get_data(b);
break;
}
}
else if(aic->args[i].direction == AICD_OUT)
switch(aic->args[i].type)
{
case AICT_VOID:
break;
case AICT_BOOL:
case AICT_INT8:
case AICT_UINT8:
p = va_arg(arg, int8_t *);
args[i] = p;
break;
case AICT_INT16:
case AICT_UINT16:
p = va_arg(arg, int16_t *);
args[i] = p;
break;
case AICT_INT32:
case AICT_UINT32:
case AICT_FLOAT:
p = va_arg(arg, int32_t *);
args[i] = p;
break;
case AICT_INT64:
case AICT_UINT64:
case AICT_DOUBLE:
p = va_arg(arg, int64_t *);
args[i] = p;
break;
case AICT_STRING:
p = va_arg(arg, String **);
args[i] = p;
break;
case AICT_BUFFER:
b = va_arg(arg, Buffer *);
args[i] = b;
break;
}
if(size == 0)
continue;
#ifdef DEBUG
fprintf(stderr, "DEBUG: => size %lu\n", (unsigned long)size);
#endif
if(_send_bytes(p, size, buf, buflen, &pos) != 0)
return -1;
}
return pos;
}
static int _send_bytes(char const * data, size_t datalen, char * buf,
size_t buflen, size_t * pos)
/* FIXME the buffer is sometimes too short */
{
if(*pos + datalen > buflen)
{
errno = ENOBUFS;
return error_set_code(-errno, "%s", strerror(errno));
}
memcpy(&buf[*pos], data, datalen);
*pos += datalen;
return 0;
}
static int _send_string(char const * string, char buf[], size_t buflen,
size_t * pos)
{
size_t i;
if(string == NULL)
/* XXX always send something until the protocol allows NULL */
string = "";
for(i = 0; *pos < buflen; i++)
{
buf[*pos] = string[i];
(*pos)++;
if(string[i] == '\0')
return 0;
}
errno = ENOBUFS;
return error_set_code(-errno, "%s", strerror(errno));
}
/* appinterface_call_receive
* PRE
* POST
* < 0 an error occured
* 0 not enough data ready
* > 0 the amount of data read */
static String * _read_string(char buf[], size_t buflen, size_t * pos);
int appinterface_call_receive(AppInterface * appinterface, int32_t * ret,
char buf[], size_t buflen, char const * function, void ** args)
{
AppInterfaceCall * aic;
size_t i;
size_t size;
void * v;
char ** p;
Buffer * b = NULL;
uint32_t bsize;
size_t pos = 0;
float * f;
int16_t * i16;
int32_t * i32;
if((aic = _appinterface_get_call(appinterface, function)) == NULL)
return -1;
#ifdef DEBUG
fprintf(stderr, "%s%s%s", "DEBUG: call \"", function, "\" receive\n");
#endif
for(i = 0; i < aic->args_cnt; i++)
{
#ifdef DEBUG
fprintf(stderr, "%s%lu%s", "DEBUG: argument ",
(unsigned long)i + 1, "\n");
#endif
if(aic->args[i].direction == AICD_IN)
continue;
v = args[i];
size = aic->args[i].size;
switch(aic->args[i].type)
{
case AICT_VOID:
case AICT_BOOL:
case AICT_INT8:
case AICT_UINT8:
case AICT_INT16:
case AICT_UINT16:
case AICT_INT32:
case AICT_UINT32:
case AICT_FLOAT:
case AICT_INT64:
case AICT_UINT64:
case AICT_DOUBLE:
break; /* nothing more to do */
case AICT_STRING:
if((v = _read_string(buf, buflen, &pos))
== NULL)
return -1;
if((p = args[i]) != NULL)
*p = v;
break;
case AICT_BUFFER: /* read the size */
b = args[i];
v = &bsize;
size = sizeof(bsize);
break;
}
if(size == 0)
continue;
if(pos + size > buflen)
return 0;
#ifdef DEBUG
fprintf(stderr, "%s%lu%s", "DEBUG: <= size ",
(unsigned long)size, "\n");
#endif
memcpy(v, &buf[pos], size);
pos += size;
size = 0;
switch(aic->args[i].type)
{
case AICT_VOID:
case AICT_BOOL:
case AICT_INT8:
case AICT_UINT8:
#ifdef DEBUG
fprintf(stderr, "%s", "DEBUG: <= int8\n");
#endif
break; /* nothing more to do */
case AICT_INT16:
case AICT_UINT16:
i16 = v;
*i16 = ntohs(*i16);
#ifdef DEBUG
fprintf(stderr, "%s%d%s", "DEBUG: <= int16",
*i16, "\n");
#endif
break;
case AICT_INT32:
case AICT_UINT32:
i32 = v;
*i32 = ntohl(*i32);
#ifdef DEBUG
fprintf(stderr, "%s%d%s", "DEBUG: <= int32",
*i32, "\n");
#endif
break;
case AICT_FLOAT:
f = v;
#ifdef DEBUG
fprintf(stderr, "%s%.1f%s", "DEBUG: <= float",
*f, "\n");
#endif
break;
case AICT_INT64:
case AICT_UINT64:
#ifdef DEBUG
fprintf(stderr, "%s", "DEBUG: <= int64\n");
#endif
break; /* FIXME wrong endian */
case AICT_DOUBLE:
#ifdef DEBUG
fprintf(stderr, "%s", "DEBUG: <= double\n");
#endif
break; /* FIXME wrong endian */
case AICT_STRING: /* already done and never reached */
break;
case AICT_BUFFER:
bsize = ntohl(bsize);
if(buffer_set_size(b, bsize) != 0)
return -1; /* not enough space in b */
size = bsize;
v = buffer_get_data(b);
#ifdef DEBUG
fprintf(stderr, "%s%lu%s", "DEBUG: <= Buffer"
" size ", (unsigned long)size,
"\n");
#endif
break;
}
if(size == 0)
continue;
if(pos + size > buflen)
return 0;
memcpy(v, &buf[pos], size);
pos += size;
}
if(pos + sizeof(*ret) > buflen) /* only the return value is left */
return 0;
if(ret != NULL) /* read the return value */
{
memcpy(ret, &buf[pos], sizeof(*ret));
*ret = ntohl(*ret);
}
return pos + sizeof(*ret);
}
/* appinterface_callv */
int appinterface_callv(AppInterface * appinterface, Variable ** result,
char const * function, size_t argc, Variable ** argv)
@ -810,512 +427,3 @@ int appinterface_callv(AppInterface * appinterface, Variable ** result,
/* FIXME implement */
return -1;
}
/* appinterface_receive */
static int _receive_args(AppInterfaceCall * call, int * ret, char buf[],
size_t buflen, size_t * pos, char bufw[], size_t bufwlen,
size_t * bufwpos);
int appinterface_receive(AppInterface * appinterface, int * ret, char buf[],
size_t buflen, char bufw[], size_t bufwlen, size_t * bufwpos)
/* FIXME should work like appinterface_call_receive */
{
size_t pos = 0;
String * func;
AppInterfaceCall * aic;
if((func = _read_string(buf, buflen, &pos)) == NULL)
return -error_set_code(1, "%s", "Could not read the name of the"
" call");
aic = _appinterface_get_call(appinterface, func);
string_delete(func);
if(aic == NULL)
return -1;
if(_receive_args(aic, ret, buf, buflen, &pos, bufw, bufwlen, bufwpos)
!= 0)
return -1;
return pos;
}
static String * _read_string(char buf[], size_t buflen, size_t * pos)
{
char * str = &buf[*pos];
for(; *pos < buflen && buf[*pos] != '\0'; (*pos)++);
if(*pos == buflen)
return NULL;
(*pos)++;
return string_new(str);
}
/* _receive_args */
static size_t _args_pre_exec(AppInterfaceCall * call, char buf[], size_t buflen,
size_t * pos, void ** args);
static int _args_exec(AppInterfaceCall * call, int * ret, void ** args);
static size_t _args_post_exec(AppInterfaceCall * call, char buf[],
size_t buflen, size_t * pos, void ** args, size_t i);
static int _receive_args(AppInterfaceCall * call, int * ret, char buf[],
size_t buflen, size_t * pos, char bufw[], size_t bufwlen,
size_t * bufwpos)
/* FIXME _args_post_exec() sends data even when _args_exec() fails */
{
void ** args;
size_t i;
if((args = malloc(sizeof(*args) * call->args_cnt)) == NULL)
return error_set_code(-errno, "%s", strerror(errno));
if((i = _args_pre_exec(call, buf, buflen, pos, args)) != call->args_cnt)
{
_args_post_exec(call, bufw, bufwlen, bufwpos, args, i);
free(args);
#ifdef DEBUG
error_print(call->name);
#endif
return 1;
}
_args_exec(call, ret, args);
if(_args_post_exec(call, bufw, bufwlen, bufwpos, args, i) != i)
{
free(args);
#ifdef DEBUG
error_print(call->name);
#endif
return 1;
}
free(args);
#ifdef DEBUG
fprintf(stderr, "%s%d%s", "DEBUG: => ", *ret, "\n");
#endif
return 0;
}
/* _args_pre_exec
* Prepares the arguments to execute the desired function */
static int _pre_exec_in(AppInterfaceCallArg * aica, char buf[], size_t buflen,
size_t * pos, void * arg);
#warning IMPLEMENT THIS
/* static int _pre_exec_in_out(AppInterfaceCallArg * aica, char buf[],
size_t buflen, size_t * pos, void * arg); */
static int _pre_exec_out(AppInterfaceCallArg * aica, void * arg);
static int _read_bytes(void * data, size_t datalen, char buf[], size_t buflen,
size_t * pos);
static size_t _args_pre_exec(AppInterfaceCall * call, char buf[], size_t buflen,
size_t * pos, void ** args)
/* FIXME check calls to _read_bytes and _read_string */
{
size_t i;
AppInterfaceCallArg * aica;
#ifdef DEBUG
fprintf(stderr, "%s%s(", "DEBUG: ", call->name);
#endif
for(i = 0; i < call->args_cnt; i++)
{
#ifdef DEBUG
fprintf(stderr, "%s", (i > 0) ? ", " : "");
#endif
aica = &call->args[i];
switch(aica->direction)
{
case AICD_IN:
#ifdef DEBUG
fputs("in ", stderr);
#endif
if(_pre_exec_in(aica, buf, buflen, pos,
&args[i]) != 0)
return i;
break;
case AICD_IN_OUT:
#warning IMPLEMENT THIS
#ifdef DEBUG
fputs("in out ", stderr);
#endif
/* if(_pre_exec_in_out(aica, buf, buflen, pos,
&args[i]) != 0) */
return i;
break;
case AICD_OUT:
#ifdef DEBUG
fputs("out ", stderr);
#endif
if(_pre_exec_out(aica, &args[i]) != 0)
return i;
break;
}
}
#ifdef DEBUG
fputs(")\n", stderr);
#endif
return i;
}
static int _pre_exec_in(AppInterfaceCallArg * aica, char buf[], size_t buflen,
size_t * pos, void * arg)
{
char ** p = arg;
float ** f = arg;
int8_t i8;
int16_t i16;
int32_t i32;
long * l = arg;
uint32_t size;
Buffer ** b;
switch(aica->type)
{
case AICT_VOID:
break;
case AICT_BOOL:
case AICT_INT8:
case AICT_UINT8:
if(_read_bytes(&i8, sizeof(i8), buf, buflen, pos) != 0)
return -1;
*l = i8;
#ifdef DEBUG
fprintf(stderr, "%ld", *l);
#endif
break;
case AICT_INT16:
case AICT_UINT16:
if(_read_bytes(&i16, sizeof(i16), buf, buflen, pos)
!= 0)
return -1;
*l = ntohs(i16);
#ifdef DEBUG
fprintf(stderr, "%ld", *l);
#endif
break;
case AICT_INT32:
case AICT_UINT32:
if(_read_bytes(&i32, sizeof(i32), buf, buflen, pos)
!= 0)
return -1;
*l = ntohl(i32);
#ifdef DEBUG
fprintf(stderr, "%ld", *l);
#endif
break;
case AICT_FLOAT:
if((*f = malloc(sizeof(**f))) == NULL)
return -1;
if(_read_bytes(*f, sizeof(**f), buf, buflen, pos) != 0)
return -1;
#ifdef DEBUG
fprintf(stderr, "%.1f", **f);
#endif
break;
case AICT_INT64: /* FIXME not supported */
case AICT_UINT64:
case AICT_DOUBLE:
errno = ENOSYS;
return error_set_code(-errno, "%s", strerror(errno));
case AICT_BUFFER:
if(_read_bytes(&size, sizeof(size), buf, buflen, pos)
!= 0)
return -1;
size = ntohl(size);
b = arg;
if((*b = buffer_new(size, NULL)) == NULL)
return -1;
if(_read_bytes(buffer_get_data(*b), size, buf, buflen,
pos) != 0)
{
buffer_delete(*b);
return -1;
}
#ifdef DEBUG
fprintf(stderr, "%s", "Buffer");
#endif
break;
case AICT_STRING:
if((*p = _read_string(buf, buflen, pos)) == NULL)
return -1;
#ifdef DEBUG
fprintf(stderr, "\"%s\"", *p);
#endif
break;
}
return 0;
}
static int _pre_exec_out(AppInterfaceCallArg * aica, void * arg)
{
char *** p;
Buffer ** b;
switch(aica->type)
{
case AICT_VOID:
break;
case AICT_BOOL:
case AICT_INT8: case AICT_UINT8:
case AICT_INT16: case AICT_UINT16:
case AICT_INT32: case AICT_UINT32:
case AICT_INT64: case AICT_UINT64:
p = arg;
if((*p = malloc(aica->size)) == NULL)
return -1;
#ifdef DEBUG
fputs(" integer", stderr);
#endif
break;
case AICT_FLOAT: case AICT_DOUBLE:
p = arg;
if((*p = malloc(aica->size)) == NULL)
return -1;
#ifdef DEBUG
fputs(" float", stderr);
#endif
break;
case AICT_BUFFER:
b = arg;
if((*b = buffer_new(0, NULL)) == NULL)
return -1;
#ifdef DEBUG
fputs("Buffer", stderr);
#endif
break;
case AICT_STRING:
p = arg;
if((*p = malloc(sizeof(**p))) == NULL)
return -1;
**p = NULL;
#ifdef DEBUG
fputs("String", stderr);
#endif
break;
}
return 0;
}
static int _read_bytes(void * data, size_t datalen, char buf[], size_t buflen,
size_t * pos)
{
if(datalen > buflen - *pos)
{
errno = EAGAIN;
return error_set_code(-errno, "%s", strerror(errno));
}
memcpy(data, &buf[*pos], datalen);
(*pos) += datalen;
return 0;
}
static int _args_exec(AppInterfaceCall * call, int * ret, void ** args)
{
int (*func0)(void);
int (*func1)(void *);
int (*func2)(void *, void *);
int (*func3)(void *, void *, void *);
int (*func4)(void *, void *, void *, void *);
switch(call->args_cnt) /* FIXME not flexible */
{
case 0:
func0 = call->func;
*ret = func0();
break;
case 1:
func1 = call->func;
*ret = func1(args[0]);
break;
case 2:
func2 = call->func;
*ret = func2(args[0], args[1]);
break;
case 3:
func3 = call->func;
*ret = func3(args[0], args[1], args[2]);
break;
case 4:
func4 = call->func;
*ret = func4(args[0], args[1], args[2], args[3]);
break;
default:
return error_set_code(1, "%s%lu%s", "AppInterface: "
"functions with ",
(unsigned long)call->args_cnt,
"arguments are not supported");
}
if(call->type.type == AICT_VOID) /* avoid information leak */
*ret = 0;
return 0;
}
/* args_post_exec
* Sends back data as necessary and frees previously allocated memory */
static int _post_exec_out(AppInterfaceCallArg * aica, char buf[], size_t buflen,
size_t * pos, void * arg);
static int _post_exec_free_in(AppInterfaceCallArg * aica, void * arg);
static int _post_exec_free_out(AppInterfaceCallArg * aica, void * arg);
static size_t _args_post_exec(AppInterfaceCall * call, char buf[],
size_t buflen, size_t * pos, void ** args, size_t i)
{
size_t ret = i;
size_t j;
AppInterfaceCallArg * aica;
if(i == call->args_cnt) /* send results */
{
for(j = 0; j < i; j++)
{
aica = &call->args[j];
switch(aica->direction)
{
case AICD_IN: /* nothing to do here */
break;
case AICD_IN_OUT:
#warning IMPLEMENT THIS
/* if(_post_exec_in_out(aica, args[j])
!= 0)
ret = j; */
break;
case AICD_OUT:
if(_post_exec_out(aica, buf, buflen,
pos, args[j])
!= 0)
ret = j;
break;
}
}
}
for(j = 0; j < i; j++) /* free arguments */
{
aica = &call->args[j];
switch(aica->direction)
{
case AICD_IN:
_post_exec_free_in(aica, args[j]);
break;
case AICD_IN_OUT:
#warning IMPLEMENT THIS
break;
case AICD_OUT:
_post_exec_free_out(aica, args[j]);
break;
}
}
return ret;
}
static int _post_exec_out(AppInterfaceCallArg * aica, char buf[], size_t buflen,
size_t * pos, void * arg)
{
int16_t * i16;
int32_t * i32;
Buffer * b;
char ** p;
uint32_t size;
if(aica->size > buflen)
{
errno = ENOBUFS;
return error_set_code(-errno, "%s", strerror(errno));
}
switch(aica->type)
{
case AICT_VOID:
break;
case AICT_BOOL:
case AICT_INT8:
case AICT_UINT8:
if(_send_bytes(arg, aica->size, buf, buflen, pos) != 0)
return -1;
break;
case AICT_INT16:
case AICT_UINT16:
i16 = arg;
*i16 = htons(*i16);
if(_send_bytes(arg, aica->size, buf, buflen, pos) != 0)
return -1;
break;
case AICT_INT32:
case AICT_UINT32:
case AICT_FLOAT:
i32 = arg;
*i32 = htonl(*i32);
if(_send_bytes(arg, aica->size, buf, buflen, pos) != 0)
return -1;
break;
case AICT_INT64: /* FIXME not supported */
case AICT_UINT64:
case AICT_DOUBLE:
errno = ENOSYS;
return error_set_code(-errno, "%s", strerror(errno));
case AICT_BUFFER:
b = arg;
size = htonl(buffer_get_size(b)); /* size of buffer */
if(_send_bytes((char*)&size, sizeof(size), buf, buflen,
pos) != 0)
return -1;
if(_send_bytes(buffer_get_data(b), buffer_get_size(b),
buf, buflen, pos) != 0)
return -1;
break;
case AICT_STRING:
p = arg;
if(_send_string(*p, buf, buflen, pos) != 0)
return -1;
break;
}
return 0;
}
static int _post_exec_free_in(AppInterfaceCallArg * aica, void * arg)
{
Buffer * b = arg;
switch(aica->type)
{
case AICT_VOID:
case AICT_BOOL:
case AICT_INT8: case AICT_UINT8:
case AICT_INT16: case AICT_UINT16:
case AICT_INT32: case AICT_UINT32:
break;
case AICT_INT64: case AICT_UINT64:
case AICT_DOUBLE:
/* FIXME not supported */
errno = ENOSYS;
return error_set_code(-errno, "%s", strerror(errno));
case AICT_BUFFER:
buffer_delete(b);
break;
case AICT_FLOAT:
case AICT_STRING:
free(arg);
break;
}
return 0;
}
static int _post_exec_free_out(AppInterfaceCallArg * aica, void * arg)
{
Buffer * b;
switch(aica->type)
{
case AICT_VOID:
break;
case AICT_BOOL:
case AICT_INT8: case AICT_UINT8:
case AICT_INT16: case AICT_UINT16:
case AICT_INT32: case AICT_UINT32:
case AICT_INT64: case AICT_UINT64:
case AICT_FLOAT: case AICT_DOUBLE:
free(arg);
break;
case AICT_BUFFER:
b = arg;
buffer_delete(b);
break;
case AICT_STRING: /* FIXME not supported */
errno = ENOSYS;
return error_set_code(-errno, "%s", strerror(errno));
}
return 0;
}

View File

@ -41,13 +41,6 @@ int appinterface_get_args_count(AppInterface * appinterface, size_t * count,
char const * function);
/* useful */
int appinterface_call(AppInterface * appinterface, char buf[], size_t buflen,
char const * function, void ** args, va_list arg);
int appinterface_call_receive(AppInterface * appinterface, int32_t * ret,
char buf[], size_t buflen, char const * function, void ** args);
int appinterface_receive(AppInterface * appinterface, int * ret, char buf[],
size_t buflen, char bufw[], size_t bufwlen, size_t * bufwpos);
int appinterface_callv(AppInterface * appinterface, Variable ** result,
char const * method, size_t argc, Variable ** argv);