working on mod-ffi
This commit is contained in:
parent
12e50d46d7
commit
8303b48fd1
@ -84,7 +84,6 @@
|
|||||||
#define FMTC_LONGLONG 'L'
|
#define FMTC_LONGLONG 'L'
|
||||||
#define FMTC_BCS 's'
|
#define FMTC_BCS 's'
|
||||||
#define FMTC_UCS 'S'
|
#define FMTC_UCS 'S'
|
||||||
#define FMTC_BLOB 'b'
|
|
||||||
#define FMTC_POINTER 'p'
|
#define FMTC_POINTER 'p'
|
||||||
|
|
||||||
#define FMTC_INT8 '1'
|
#define FMTC_INT8 '1'
|
||||||
@ -489,6 +488,7 @@ static int fnc_close (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
static HAWK_INLINE int add_ffi_arg (hawk_rtx_t* rtx, ffi_t* ffi, hawk_ooch_t fmtc, int _unsigned, hawk_val_t* arg)
|
static HAWK_INLINE int add_ffi_arg (hawk_rtx_t* rtx, ffi_t* ffi, hawk_ooch_t fmtc, int _unsigned, hawk_val_t* arg)
|
||||||
{
|
{
|
||||||
#if defined(USE_LIBFFI)
|
#if defined(USE_LIBFFI)
|
||||||
@ -719,18 +719,10 @@ static HAWK_INLINE int add_ffi_arg (hawk_rtx_t* rtx, ffi_t* ffi, hawk_ooch_t fmt
|
|||||||
case FMTC_BCS:
|
case FMTC_BCS:
|
||||||
{
|
{
|
||||||
hawk_bch_t* ptr;
|
hawk_bch_t* ptr;
|
||||||
|
hawk_oow_t len;
|
||||||
|
|
||||||
if (!HAWK_OBJ_IS_CHAR_POINTER(arg)) goto inval_arg_value;
|
ptr = hawk_rtx_getvalbcstr(rtx, arg, &len);
|
||||||
|
if(HAWK_UNLIKELY(!ptr)) goto inval_arg_value;
|
||||||
#if defined(HAWK_OOCH_IS_UCH)
|
|
||||||
ptr = hawk_dupootobcharswithheadroom(hawk, HAWK_SIZEOF_VOID_P, HAWK_OBJ_GET_CHAR_SLOT(arg), HAWK_OBJ_GET_SIZE(arg), HAWK_NULL);
|
|
||||||
if (!ptr) goto oops; /* out of system memory or conversion error - soft failure */
|
|
||||||
link_ca (ffi, ptr);
|
|
||||||
#else
|
|
||||||
ptr = HAWK_OBJ_GET_CHAR_SLOT(arg);
|
|
||||||
/*ptr = hawk_dupoochars(hawk, HAWK_OBJ_GET_CHAR_SLOT(arg), HAWK_OBJ_GET_SIZE(arg));
|
|
||||||
if (!ptr) goto oops;*/ /* out of system memory or conversion error - soft failure */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(USE_DYNCALL)
|
#if defined(USE_DYNCALL)
|
||||||
dcArgPointer (ffi->dc, ptr);
|
dcArgPointer (ffi->dc, ptr);
|
||||||
@ -744,34 +736,11 @@ static HAWK_INLINE int add_ffi_arg (hawk_rtx_t* rtx, ffi_t* ffi, hawk_ooch_t fmt
|
|||||||
case FMTC_UCS:
|
case FMTC_UCS:
|
||||||
{
|
{
|
||||||
hawk_uch_t* ptr;
|
hawk_uch_t* ptr;
|
||||||
|
hawk_oow_t len;
|
||||||
|
|
||||||
if (!HAWK_OBJ_IS_CHAR_POINTER(arg)) goto inval_arg_value;
|
ptr = hawk_rtx_valtoucstrdup(rtx, arg, &len);
|
||||||
|
if(HAWK_UNLIKELY(!ptr)) goto inval_arg_value;
|
||||||
|
|
||||||
#if defined(HAWK_OOCH_IS_UCH)
|
|
||||||
ptr = HAWK_OBJ_GET_CHAR_SLOT(arg);
|
|
||||||
/*ptr = hawk_dupoochars(hawk, HAWK_OBJ_GET_CHAR_SLOT(arg), HAWK_OBJ_GET_SIZE(arg));
|
|
||||||
if (!ptr) goto oops; */ /* out of system memory or conversion error - soft failure */
|
|
||||||
#else
|
|
||||||
ptr = hawk_dupootoucharswithheadroom(hawk, HAWK_SIZEOF_VOID_P, HAWK_OBJ_GET_CHAR_SLOT(arg), HAWK_OBJ_GET_SIZE(arg), HAWK_NULL);
|
|
||||||
if (!ptr) goto oops; /* out of system memory or conversion error - soft failure */
|
|
||||||
link_ca (ffi, ptr);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(USE_DYNCALL)
|
|
||||||
dcArgPointer (ffi->dc, ptr);
|
|
||||||
#elif defined(USE_LIBFFI)
|
|
||||||
ffi->arg_values[ffi->arg_count] = &ffi->arg_svs[ffi->arg_count].p;
|
|
||||||
ffi->arg_svs[ffi->arg_count].p = ptr;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case FMTC_BLOB:
|
|
||||||
{
|
|
||||||
void* ptr;
|
|
||||||
|
|
||||||
if (HAWK_OBJ_IS_BYTE_POINTER(arg)) goto inval_arg_value;
|
|
||||||
ptr = HAWK_OBJ_GET_BYTE_SLOT(arg);
|
|
||||||
|
|
||||||
#if defined(USE_DYNCALL)
|
#if defined(USE_DYNCALL)
|
||||||
dcArgPointer (ffi->dc, ptr);
|
dcArgPointer (ffi->dc, ptr);
|
||||||
@ -782,6 +751,7 @@ static HAWK_INLINE int add_ffi_arg (hawk_rtx_t* rtx, ffi_t* ffi, hawk_ooch_t fmt
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
case FMTC_POINTER:
|
case FMTC_POINTER:
|
||||||
{
|
{
|
||||||
void* ptr;
|
void* ptr;
|
||||||
@ -798,6 +768,7 @@ static HAWK_INLINE int add_ffi_arg (hawk_rtx_t* rtx, ffi_t* ffi, hawk_ooch_t fmt
|
|||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
inval_sig_ch:
|
inval_sig_ch:
|
||||||
@ -813,47 +784,79 @@ static HAWK_INLINE int add_ffi_arg (hawk_rtx_t* rtx, ffi_t* ffi, hawk_ooch_t fmt
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
inval_arg_value:
|
inval_arg_value:
|
||||||
hawk_seterrbfmt (hawk, HAWK_EINVAL, "invalid argument value - %O", arg);
|
hawk_rtx_seterrbfmt (rtx, HAWK_NULL, HAWK_EINVAL, "invalid argument value - %O", arg);
|
||||||
|
|
||||||
oops:
|
oops:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#if 0
|
static int fnc_call (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
||||||
static hawk_pfrc_t fnc_call (hawk_t* hawk, hawk_mod_t* mod, hawk_ooi_t nargs)
|
|
||||||
{
|
{
|
||||||
#if defined(USE_DYNCALL) || defined(USE_LIBFFI)
|
#if 0
|
||||||
ffi_t* ffi;
|
hawk_t* hawk = hawk_rtx_gethawk(rtx);
|
||||||
hawk_oop_t fun, sig, args;
|
ffi_list_t* ffi_list;
|
||||||
|
ffi_node_t* ffi_node;
|
||||||
|
hawk_int_t ret = -1;
|
||||||
|
|
||||||
|
hawk_val_t* a2;
|
||||||
|
hawk_oocs_t fun;
|
||||||
|
void* funx;
|
||||||
|
|
||||||
|
hawk_val_t* a3;
|
||||||
|
hawk_oocs_t sig;
|
||||||
|
|
||||||
hawk_oow_t i, j, nfixedargs, _unsigned;
|
hawk_oow_t i, j, nfixedargs, _unsigned;
|
||||||
void* f;
|
|
||||||
hawk_oop_oop_t arr;
|
|
||||||
int vbar = 0;
|
int vbar = 0;
|
||||||
hawk_ooch_t fmtc;
|
hawk_ooch_t fmtc;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
hawk_oop_t fun, sig, args;
|
||||||
|
void* f;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(USE_LIBFFI)
|
#if defined(USE_LIBFFI)
|
||||||
ffi_status fs;
|
ffi_status fs;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ffi = (ffi_t*)hawk_getobjtrailer(hawk, HAWK_STACK_GETRCV(hawk, nargs), HAWK_NULL);
|
|
||||||
|
|
||||||
fun = HAWK_STACK_GETARG(hawk, nargs, 0);
|
|
||||||
sig = HAWK_STACK_GETARG(hawk, nargs, 1);
|
|
||||||
args = HAWK_STACK_GETARG(hawk, nargs, 2);
|
|
||||||
|
|
||||||
if (hawk_ptrtooow(hawk, fun, (hawk_oow_t*)&f) <= -1) goto softfail;
|
|
||||||
|
|
||||||
/* the signature must not be empty. at least the return type must be
|
|
||||||
* specified */
|
|
||||||
if (!HAWK_OBJ_IS_CHAR_POINTER(sig) || HAWK_OBJ_GET_SIZE(sig) <= 0) goto inval;
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* TODO: check if arr is a kind of array??? or check if it's indexed */
|
|
||||||
if (HAWK_OBJ_GET_SIZE(sig) > 1 && HAWK_CLASSOF(hawk,args) != hawk->_array) goto inval;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
arr = (hawk_oop_oop_t)args;
|
/* ffi::call (ffi-handle, return-value, "function name", "signature", argument....); */
|
||||||
/*HAWK_DEBUG2 (hawk, "<ffi.call> %p in %p\n", f, ffi->handle);*/
|
ffi_list = rtx_to_ffi_list(rtx, fi);
|
||||||
|
ffi_node = get_ffi_list_node_with_arg(rtx, ffi_list, hawk_rtx_getarg(rtx, 0), &ret);
|
||||||
|
if (!ffi_node) goto done;
|
||||||
|
|
||||||
|
a2 = hawk_rtx_getarg(rtx, 2);
|
||||||
|
fun.ptr = hawk_rtx_getvaloocstr(rtx, a2, &fun.len);
|
||||||
|
if (!fun.ptr)
|
||||||
|
{
|
||||||
|
ret = copy_error_to_ffi_list (rtx, ffi_list);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
a3 = hawk_rtx_getarg(rtx, 3);
|
||||||
|
sig.ptr = hawk_rtx_getvaloocstr(rtx, a3, &sig.len);
|
||||||
|
if (!sig.ptr)
|
||||||
|
{
|
||||||
|
ret = copy_error_to_ffi_list (rtx, ffi_list);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hawk_count_oocstr(fun.ptr) != fun.len)
|
||||||
|
{
|
||||||
|
ret = set_error_on_ffi_list(rtx, ffi_list, HAWK_EINVAL, HAWK_T("invalid function name - %.*js"), fun.len, fun.ptr);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
funx = hawk->prm.modgetsym(hawk, ffi_node->ffi.handle, fun.ptr);
|
||||||
|
if (!funx)
|
||||||
|
{
|
||||||
|
const hawk_ooch_t* olderr = hawk_backuperrmsg(hawk);
|
||||||
|
ret = set_error_on_ffi_list(rtx, ffi_list, HAWK_ENOENT, HAWK_T("unable to find function %js - %js "), fun.ptr, olderr);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(USE_DYNCALL)
|
#if defined(USE_DYNCALL)
|
||||||
dcMode (ffi->dc, DC_CALL_C_DEFAULT);
|
dcMode (ffi->dc, DC_CALL_C_DEFAULT);
|
||||||
@ -873,17 +876,15 @@ static hawk_pfrc_t fnc_call (hawk_t* hawk, hawk_mod_t* mod, hawk_ooi_t nargs)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
ffi->arg_count = 0;
|
ffi_node->ffi.arg_count = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* check argument signature */
|
/* check argument signature */
|
||||||
for (i = 0, j = 0, nfixedargs = 0, _unsigned = 0; i < HAWK_OBJ_GET_SIZE(sig); i++)
|
for (i = 0, j = 4, nfixedargs = 0, _unsigned = 0; i < sig.len; i++)
|
||||||
{
|
{
|
||||||
fmtc = HAWK_OBJ_GET_CHAR_VAL(sig, i);
|
fmtc = sig.ptr[i];
|
||||||
if (fmtc == ' ')
|
if (fmtc == ' ') continue;
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (fmtc == '>')
|
if (fmtc == '>')
|
||||||
{
|
{
|
||||||
i++;
|
i++;
|
||||||
@ -911,26 +912,27 @@ static hawk_pfrc_t fnc_call (hawk_t* hawk, hawk_mod_t* mod, hawk_ooi_t nargs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* more items in signature than the actual argument */
|
/* more items in signature than the actual argument */
|
||||||
if (j >= HAWK_OBJ_GET_SIZE(arr)) goto inval;
|
if (j >= hawk_rtx_getnargs(rtx)) goto inval;
|
||||||
|
|
||||||
if (add_ffi_arg(hawk, ffi, fmtc, _unsigned, HAWK_OBJ_GET_OOP_VAL(arr, j)) <= -1) goto softfail;
|
if (add_ffi_arg(hawk, &ffi_node->ffi, fmtc, _unsigned, hawk_rtx_getarg(rtx, j), &ret) <= -1) goto done;
|
||||||
_unsigned = 0;
|
_unsigned = 0;
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (i < HAWK_OBJ_GET_SIZE(sig) && HAWK_OBJ_GET_CHAR_VAL(sig, i) == ' ') i++; /* skip all spaces after > */
|
while (i < sig.len && sig.ptr[i] == ' ') i++; /* skip all spaces after > */
|
||||||
|
|
||||||
|
fmtc = (i >= sig.len)? FMTC_NULL: sig.ptr[i];
|
||||||
|
|
||||||
fmtc = (i >= HAWK_OBJ_GET_SIZE(sig)? FMTC_NULL: HAWK_OBJ_GET_CHAR_VAL(sig, i));
|
|
||||||
#if defined(USE_LIBFFI)
|
#if defined(USE_LIBFFI)
|
||||||
fs = (nfixedargs == j)? ffi_prep_cif(&ffi->cif, FFI_DEFAULT_ABI, j, ffi->fmtc_to_type[0][fmtc], ffi->arg_types):
|
fs = (nfixedargs == j)? ffi_prep_cif(&ffi_node->ffi.cif, FFI_DEFAULT_ABI, j, ffi_node->ffi.fmtc_to_type[0][fmtc], ffi_node->ffi.arg_types):
|
||||||
ffi_prep_cif_var(&ffi->cif, FFI_DEFAULT_ABI, nfixedargs, j, ffi->fmtc_to_type[0][fmtc], ffi->arg_types);
|
ffi_prep_cif_var(&ffi_node->ffi.cif, FFI_DEFAULT_ABI, nfixedargs, j, ffi_node->ffi.fmtc_to_type[0][fmtc], ffi_node->ffi.arg_types);
|
||||||
if (fs != FFI_OK)
|
if (fs != FFI_OK)
|
||||||
{
|
{
|
||||||
hawk_seterrnum (hawk, HAWK_ESYSERR);
|
hawk_seterrnum (hawk, HAWK_ESYSERR);
|
||||||
goto softfail;
|
goto softfail;
|
||||||
}
|
}
|
||||||
|
|
||||||
ffi_call (&ffi->cif, FFI_FN(f), &ffi->ret_sv, ffi->arg_values);
|
ffi_call (&ffi_node->ffi.cif, FFI_FN(f), &ffi_node->ffi.ret_sv, ffi_node->ffi.arg_values);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (fmtc == 'u')
|
if (fmtc == 'u')
|
||||||
@ -1226,17 +1228,6 @@ static hawk_pfrc_t fnc_call (hawk_t* hawk, hawk_mod_t* mod, hawk_ooi_t nargs)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
case FMTC_BLOB:
|
|
||||||
{
|
|
||||||
/* blob as a return type isn't sufficient as it lacks the size information.
|
|
||||||
* blob as an argument is just a pointer and the size can be yet another argument.
|
|
||||||
* it there a good way to represent this here?... TODO: */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
case FMTC_POINTER:
|
case FMTC_POINTER:
|
||||||
{
|
{
|
||||||
void* r;
|
void* r;
|
||||||
@ -1266,72 +1257,13 @@ static hawk_pfrc_t fnc_call (hawk_t* hawk, hawk_mod_t* mod, hawk_ooi_t nargs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
free_linked_cas (hawk, ffi);
|
free_linked_cas (hawk, ffi);
|
||||||
return HAWK_PF_SUCCESS;
|
|
||||||
|
|
||||||
noimpl:
|
done:
|
||||||
hawk_seterrnum (hawk, HAWK_ENOIMPL);
|
hawk_rtx_setretval (rtx, hawk_rtx_makeintval(ret));
|
||||||
goto softfail;
|
return 0;
|
||||||
|
|
||||||
inval:
|
|
||||||
hawk_seterrnum (hawk, HAWK_EINVAL);
|
|
||||||
goto softfail;
|
|
||||||
|
|
||||||
softfail:
|
|
||||||
free_linked_cas (hawk, ffi);
|
|
||||||
HAWK_STACK_SETRETTOERRNUM (hawk, nargs);
|
|
||||||
return HAWK_PF_SUCCESS;
|
|
||||||
|
|
||||||
hardfail:
|
|
||||||
free_linked_cas (hawk, ffi);
|
|
||||||
return HAWK_PF_HARD_FAILURE;
|
|
||||||
|
|
||||||
#else
|
|
||||||
hawk_seterrnum (hawk, HAWK_ENOIMPL);
|
|
||||||
HAWK_STACK_SETRETTOERRNUM (hawk, nargs);
|
|
||||||
return HAWK_PF_SUCCESS;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static hawk_pfrc_t fnc_getsym (hawk_t* hawk, hawk_mod_t* mod, hawk_ooi_t nargs)
|
|
||||||
{
|
|
||||||
ffi_t* ffi;
|
|
||||||
hawk_oop_t name, ret;
|
|
||||||
void* sym;
|
|
||||||
|
|
||||||
HAWK_ASSERT (hawk, nargs == 1);
|
|
||||||
|
|
||||||
ffi = (ffi_t*)hawk_getobjtrailer(hawk, HAWK_STACK_GETRCV(hawk, nargs), HAWK_NULL);
|
|
||||||
name = HAWK_STACK_GETARG(hawk, nargs, 0);
|
|
||||||
|
|
||||||
if (!HAWK_OBJ_IS_CHAR_POINTER(name))
|
|
||||||
{
|
|
||||||
hawk_seterrnum (hawk, HAWK_EINVAL);
|
|
||||||
goto softfail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hawk->vmprim.dl_getsym)
|
|
||||||
{
|
|
||||||
hawk_seterrnum (hawk, HAWK_ENOIMPL);
|
|
||||||
goto softfail;
|
|
||||||
}
|
|
||||||
|
|
||||||
sym = hawk->vmprim.dl_getsym(hawk, ffi->handle, HAWK_OBJ_GET_CHAR_SLOT(name));
|
|
||||||
if (!sym) goto softfail;
|
|
||||||
|
|
||||||
HAWK_DEBUG4 (hawk, "<ffi.getsym> %.*js => %p in %p\n", HAWK_OBJ_GET_SIZE(name), HAWK_OBJ_GET_CHAR_SLOT(name), sym, ffi->handle);
|
|
||||||
|
|
||||||
ret = hawk_oowtoptr(hawk, (hawk_oow_t)sym);
|
|
||||||
if (!ret) goto softfail;
|
|
||||||
|
|
||||||
HAWK_STACK_SETRET (hawk, nargs, ret);
|
|
||||||
return HAWK_PF_SUCCESS;
|
|
||||||
|
|
||||||
softfail:
|
|
||||||
HAWK_STACK_SETRETTOERRNUM (hawk, nargs);
|
|
||||||
return HAWK_PF_SUCCESS;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int fnc_errmsg (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
static int fnc_errmsg (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
||||||
{
|
{
|
||||||
ffi_list_t* ffi_list;
|
ffi_list_t* ffi_list;
|
||||||
@ -1345,15 +1277,14 @@ static int fnc_errmsg (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* ------------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------------ */
|
||||||
|
#define A_MAX HAWK_TYPE_MAX(hawk_oow_t)
|
||||||
|
|
||||||
static hawk_mod_fnc_tab_t fnctab[] =
|
static hawk_mod_fnc_tab_t fnctab[] =
|
||||||
{
|
{
|
||||||
//{ HAWK_T("call"), { { 3, 3, HAWK_NULL }, fnc_call, 0 } },
|
{ HAWK_T("call"), { { 4, A_MAX, HAWK_NULL }, fnc_call, 0 } },
|
||||||
{ HAWK_T("close"), { { 1, 1, HAWK_NULL }, fnc_close, 0 } },
|
{ HAWK_T("close"), { { 1, 1, HAWK_NULL }, fnc_close, 0 } },
|
||||||
{ HAWK_T("errmsg"), { { 0, 0, HAWK_NULL }, fnc_errmsg, 0 } },
|
{ HAWK_T("errmsg"), { { 0, 0, HAWK_NULL }, fnc_errmsg, 0 } },
|
||||||
//{ HAWK_T("getsym"), { { 1, 1, HAWK_NULL }, fnc_getsym, 0 } },
|
|
||||||
{ HAWK_T("open"), { { 1, 1, HAWK_NULL }, fnc_open, 0 } }
|
{ HAWK_T("open"), { { 1, 1, HAWK_NULL }, fnc_open, 0 } }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------------ */
|
||||||
|
Loading…
Reference in New Issue
Block a user