Extend function calling API for natives and allow catching exceptions.
Change sourcepawn url.
This commit is contained in:
parent
b31375f087
commit
19019d3a4b
@ -16,7 +16,7 @@ for cxx in builder.targets:
|
|||||||
'SM_DEFAULT_THREADER',
|
'SM_DEFAULT_THREADER',
|
||||||
'SM_LOGIC'
|
'SM_LOGIC'
|
||||||
]
|
]
|
||||||
|
|
||||||
if binary.compiler.target.platform == 'linux':
|
if binary.compiler.target.platform == 'linux':
|
||||||
binary.compiler.postlink += ['-lpthread', '-lrt']
|
binary.compiler.postlink += ['-lpthread', '-lrt']
|
||||||
elif binary.compiler.target.platform == 'mac':
|
elif binary.compiler.target.platform == 'mac':
|
||||||
@ -86,6 +86,7 @@ for cxx in builder.targets:
|
|||||||
'DatabaseConfBuilder.cpp',
|
'DatabaseConfBuilder.cpp',
|
||||||
'LumpManager.cpp',
|
'LumpManager.cpp',
|
||||||
'smn_entitylump.cpp',
|
'smn_entitylump.cpp',
|
||||||
|
'NativeInvoker.cpp',
|
||||||
]
|
]
|
||||||
|
|
||||||
if binary.compiler.target.arch == 'x86_64':
|
if binary.compiler.target.arch == 'x86_64':
|
||||||
|
321
core/logic/NativeInvoker.cpp
Normal file
321
core/logic/NativeInvoker.cpp
Normal file
@ -0,0 +1,321 @@
|
|||||||
|
// vim: set sts=2 ts=8 sw=2 tw=99 et:
|
||||||
|
//
|
||||||
|
// Copyright (C) 2006-2015 AlliedModders LLC
|
||||||
|
//
|
||||||
|
// This file is part of SourcePawn. SourcePawn is free software: you can
|
||||||
|
// redistribute it and/or modify it under the terms of the GNU General Public
|
||||||
|
// License as published by the Free Software Foundation, either version 3 of
|
||||||
|
// the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License along with
|
||||||
|
// SourcePawn. If not, see http://www.gnu.org/licenses/.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "NativeInvoker.h"
|
||||||
|
|
||||||
|
/********************
|
||||||
|
* FUNCTION CALLING *
|
||||||
|
********************/
|
||||||
|
|
||||||
|
NativeInvoker::NativeInvoker(IPluginContext *pContext, const ke::RefPtr<Native> &native)
|
||||||
|
: context_(pContext),
|
||||||
|
m_curparam(0),
|
||||||
|
m_errorstate(SP_ERROR_NONE),
|
||||||
|
native_(native)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NativeInvoker::~NativeInvoker()
|
||||||
|
{
|
||||||
|
Cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
NativeInvoker::IsRunnable()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPluginContext *
|
||||||
|
NativeInvoker::GetParentContext()
|
||||||
|
{
|
||||||
|
return context_;
|
||||||
|
}
|
||||||
|
|
||||||
|
int NativeInvoker::PushCell(cell_t cell)
|
||||||
|
{
|
||||||
|
if (m_curparam >= SP_MAX_EXEC_PARAMS)
|
||||||
|
return SetError(SP_ERROR_PARAMS_MAX);
|
||||||
|
|
||||||
|
m_info[m_curparam].marked = false;
|
||||||
|
m_params[m_curparam] = cell;
|
||||||
|
m_curparam++;
|
||||||
|
|
||||||
|
return SP_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
NativeInvoker::PushCellByRef(cell_t *cell, int flags)
|
||||||
|
{
|
||||||
|
return PushArray(cell, 1, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
NativeInvoker::PushFloat(float number)
|
||||||
|
{
|
||||||
|
cell_t val = sp::FloatCellUnion(number).cell;
|
||||||
|
|
||||||
|
return PushCell(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
NativeInvoker::PushFloatByRef(float *number, int flags)
|
||||||
|
{
|
||||||
|
return PushCellByRef((cell_t *)number, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
NativeInvoker::PushArray(cell_t *inarray, unsigned int cells, int copyback)
|
||||||
|
{
|
||||||
|
if (m_curparam >= SP_MAX_EXEC_PARAMS)
|
||||||
|
{
|
||||||
|
return SetError(SP_ERROR_PARAMS_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
ParamInfo *info = &m_info[m_curparam];
|
||||||
|
|
||||||
|
info->flags = inarray ? copyback : 0;
|
||||||
|
info->marked = true;
|
||||||
|
info->size = cells;
|
||||||
|
info->str.is_sz = false;
|
||||||
|
info->orig_addr = inarray;
|
||||||
|
|
||||||
|
m_curparam++;
|
||||||
|
|
||||||
|
return SP_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
NativeInvoker::PushString(const char *string)
|
||||||
|
{
|
||||||
|
return _PushString(string, SM_PARAM_STRING_COPY, 0, strlen(string)+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
NativeInvoker::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
|
||||||
|
{
|
||||||
|
return _PushString(buffer, sz_flags, cp_flags, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
NativeInvoker::_PushString(const char *string, int sz_flags, int cp_flags, size_t len)
|
||||||
|
{
|
||||||
|
if (m_curparam >= SP_MAX_EXEC_PARAMS)
|
||||||
|
return SetError(SP_ERROR_PARAMS_MAX);
|
||||||
|
|
||||||
|
ParamInfo *info = &m_info[m_curparam];
|
||||||
|
|
||||||
|
info->marked = true;
|
||||||
|
info->orig_addr = (cell_t *)string;
|
||||||
|
info->flags = cp_flags;
|
||||||
|
info->size = len;
|
||||||
|
info->str.sz_flags = sz_flags;
|
||||||
|
info->str.is_sz = true;
|
||||||
|
|
||||||
|
m_curparam++;
|
||||||
|
|
||||||
|
return SP_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NativeInvoker::Cancel()
|
||||||
|
{
|
||||||
|
if (!m_curparam)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_errorstate = SP_ERROR_NONE;
|
||||||
|
m_curparam = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
NativeInvoker::Execute(cell_t *result, cell_t buffer, cell_t size)
|
||||||
|
{
|
||||||
|
context_->ClearLastNativeError();
|
||||||
|
|
||||||
|
// For backward compatibility, we have to clear the exception state.
|
||||||
|
// Otherwise code like this:
|
||||||
|
//
|
||||||
|
// static cell_t native(cx, params) {
|
||||||
|
// for (auto callback : callbacks) {
|
||||||
|
// callback->Execute();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Could unintentionally leak a pending exception back to the caller,
|
||||||
|
// which wouldn't have happened before the Great Exception Refactoring.
|
||||||
|
|
||||||
|
SourcePawn::ExceptionHandler eh(context_);
|
||||||
|
eh.Debug(!size);
|
||||||
|
|
||||||
|
if (!Invoke(result)) {
|
||||||
|
if(size)
|
||||||
|
context_->StringToLocalUTF8(buffer, size, eh.Message(), NULL);
|
||||||
|
int Err = context_->GetLastNativeError();
|
||||||
|
context_->ClearLastNativeError();
|
||||||
|
return Err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SP_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
NativeInvoker::Invoke(cell_t *result)
|
||||||
|
{
|
||||||
|
if (!IsRunnable()) {
|
||||||
|
Cancel();
|
||||||
|
context_->ReportErrorNumber(SP_ERROR_NOT_RUNNABLE);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (int err = m_errorstate) {
|
||||||
|
Cancel();
|
||||||
|
context_->ReportErrorNumber(err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//This is for re-entrancy!
|
||||||
|
cell_t _temp_params[SP_MAX_EXEC_PARAMS + 1];
|
||||||
|
cell_t *temp_params = &_temp_params[1];
|
||||||
|
ParamInfo temp_info[SP_MAX_EXEC_PARAMS];
|
||||||
|
unsigned int numparams = m_curparam;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
if (numparams)
|
||||||
|
{
|
||||||
|
//Save the info locally, then reset it for re-entrant calls.
|
||||||
|
memcpy(temp_info, m_info, numparams * sizeof(ParamInfo));
|
||||||
|
}
|
||||||
|
m_curparam = 0;
|
||||||
|
|
||||||
|
/* Initialize 0th parameter */
|
||||||
|
_temp_params[0] = numparams;
|
||||||
|
|
||||||
|
/* Browse the parameters and build arrays */
|
||||||
|
bool ok = true;
|
||||||
|
for (i=0; i<numparams; i++) {
|
||||||
|
/* Is this marked as an array? */
|
||||||
|
if (temp_info[i].marked) {
|
||||||
|
if (!temp_info[i].str.is_sz) {
|
||||||
|
/* Allocate a normal/generic array */
|
||||||
|
int err = context_->HeapAlloc(
|
||||||
|
temp_info[i].size,
|
||||||
|
&(temp_info[i].local_addr),
|
||||||
|
&(temp_info[i].phys_addr));
|
||||||
|
if (err != SP_ERROR_NONE) {
|
||||||
|
context_->ReportErrorNumber(err);
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (temp_info[i].orig_addr)
|
||||||
|
{
|
||||||
|
memcpy(temp_info[i].phys_addr, temp_info[i].orig_addr, sizeof(cell_t) * temp_info[i].size);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Calculate cells required for the string */
|
||||||
|
size_t cells = (temp_info[i].size + sizeof(cell_t) - 1) / sizeof(cell_t);
|
||||||
|
|
||||||
|
/* Allocate the buffer */
|
||||||
|
int err = context_->HeapAlloc(
|
||||||
|
cells,
|
||||||
|
&(temp_info[i].local_addr),
|
||||||
|
&(temp_info[i].phys_addr));
|
||||||
|
if (err != SP_ERROR_NONE) {
|
||||||
|
context_->ReportErrorNumber(err);
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy original string if necessary */
|
||||||
|
if ((temp_info[i].str.sz_flags & SM_PARAM_STRING_COPY) && (temp_info[i].orig_addr != NULL))
|
||||||
|
{
|
||||||
|
/* Cut off UTF-8 properly */
|
||||||
|
if (temp_info[i].str.sz_flags & SM_PARAM_STRING_UTF8) {
|
||||||
|
context_->StringToLocalUTF8(
|
||||||
|
temp_info[i].local_addr,
|
||||||
|
temp_info[i].size,
|
||||||
|
(const char *)temp_info[i].orig_addr,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
/* Copy a binary blob */
|
||||||
|
else if (temp_info[i].str.sz_flags & SM_PARAM_STRING_BINARY)
|
||||||
|
{
|
||||||
|
memmove(temp_info[i].phys_addr, temp_info[i].orig_addr, temp_info[i].size);
|
||||||
|
}
|
||||||
|
/* Copy ASCII characters */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context_->StringToLocal(
|
||||||
|
temp_info[i].local_addr,
|
||||||
|
temp_info[i].size,
|
||||||
|
(const char *)temp_info[i].orig_addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} /* End array/string calculation */
|
||||||
|
/* Update the pushed parameter with the byref local address */
|
||||||
|
temp_params[i] = temp_info[i].local_addr;
|
||||||
|
} else {
|
||||||
|
/* Just copy the value normally */
|
||||||
|
temp_params[i] = m_params[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make the call if we can */
|
||||||
|
if (ok)
|
||||||
|
{
|
||||||
|
*result = native_->func()(context_, _temp_params);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* i should be equal to the last valid parameter + 1 */
|
||||||
|
bool docopies = ok;
|
||||||
|
while (i--) {
|
||||||
|
if (!temp_info[i].marked)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (docopies && (temp_info[i].flags & SM_PARAM_COPYBACK)) {
|
||||||
|
if (temp_info[i].orig_addr) {
|
||||||
|
if (temp_info[i].str.is_sz) {
|
||||||
|
memcpy(temp_info[i].orig_addr, temp_info[i].phys_addr, temp_info[i].size);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (temp_info[i].size == 1) {
|
||||||
|
*temp_info[i].orig_addr = *(temp_info[i].phys_addr);
|
||||||
|
} else {
|
||||||
|
memcpy(temp_info[i].orig_addr,
|
||||||
|
temp_info[i].phys_addr,
|
||||||
|
temp_info[i].size * sizeof(cell_t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (int err = context_->HeapPop(temp_info[i].local_addr))
|
||||||
|
context_->ReportErrorNumber(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return context_->GetLastNativeError() == SP_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
NativeInvoker::SetError(int err)
|
||||||
|
{
|
||||||
|
m_errorstate = err;
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
int NativeInvoker::CallFunction(const cell_t *params, unsigned int num_params, cell_t *result) { return 0; }
|
||||||
|
funcid_t NativeInvoker::GetFunctionID() { return 0; }
|
||||||
|
int NativeInvoker::Execute2(IPluginContext *ctx, cell_t *result) { return 0; }
|
||||||
|
int NativeInvoker::CallFunction2(IPluginContext *ctx, const cell_t *params, unsigned int num_params, cell_t *result) { return 0; }
|
||||||
|
IPluginRuntime *NativeInvoker::GetParentRuntime() { return NULL; }
|
79
core/logic/NativeInvoker.h
Normal file
79
core/logic/NativeInvoker.h
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
// vim: set sts=2 ts=8 sw=2 tw=99 et:
|
||||||
|
//
|
||||||
|
// Copyright (C) 2006-2015 AlliedModders LLC
|
||||||
|
//
|
||||||
|
// This file is part of SourcePawn. SourcePawn is free software: you can
|
||||||
|
// redistribute it and/or modify it under the terms of the GNU General Public
|
||||||
|
// License as published by the Free Software Foundation, either version 3 of
|
||||||
|
// the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License along with
|
||||||
|
// SourcePawn. If not, see http://www.gnu.org/licenses/.
|
||||||
|
//
|
||||||
|
#ifndef _INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_
|
||||||
|
#define _INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_
|
||||||
|
|
||||||
|
#include <sp_vm_api.h>
|
||||||
|
#include <amtl/am-autoptr.h>
|
||||||
|
#include <amtl/am-refcounting.h>
|
||||||
|
#include "Native.h"
|
||||||
|
|
||||||
|
struct ParamInfo
|
||||||
|
{
|
||||||
|
int flags; /* Copy-back flags */
|
||||||
|
bool marked; /* Whether this is marked as being used */
|
||||||
|
cell_t local_addr; /* Local address to free */
|
||||||
|
cell_t *phys_addr; /* Physical address of our copy */
|
||||||
|
cell_t *orig_addr; /* Original address to copy back to */
|
||||||
|
ucell_t size; /* Size of array in bytes */
|
||||||
|
struct {
|
||||||
|
bool is_sz; /* is a string */
|
||||||
|
int sz_flags; /* has sz flags */
|
||||||
|
} str;
|
||||||
|
};
|
||||||
|
|
||||||
|
class NativeInvoker : public IPluginFunction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NativeInvoker(IPluginContext *pContext, const ke::RefPtr<Native> &native);
|
||||||
|
virtual ~NativeInvoker();
|
||||||
|
|
||||||
|
public:
|
||||||
|
int PushCell(cell_t cell);
|
||||||
|
int PushCellByRef(cell_t *cell, int flags);
|
||||||
|
int PushFloat(float number);
|
||||||
|
int PushFloatByRef(float *number, int flags);
|
||||||
|
int PushArray(cell_t *inarray, unsigned int cells, int copyback);
|
||||||
|
int PushString(const char *string);
|
||||||
|
int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags);
|
||||||
|
int Execute(cell_t *result, cell_t buffer=0, cell_t size=0);
|
||||||
|
void Cancel();
|
||||||
|
int CallFunction(const cell_t *params, unsigned int num_params, cell_t *result);
|
||||||
|
IPluginContext *GetParentContext();
|
||||||
|
bool Invoke(cell_t *result);
|
||||||
|
bool IsRunnable();
|
||||||
|
funcid_t GetFunctionID();
|
||||||
|
int Execute2(IPluginContext *ctx, cell_t *result);
|
||||||
|
int CallFunction2(IPluginContext *ctx,
|
||||||
|
const cell_t *params,
|
||||||
|
unsigned int num_params,
|
||||||
|
cell_t *result);
|
||||||
|
IPluginRuntime *GetParentRuntime();
|
||||||
|
const char *DebugName() {
|
||||||
|
return native_->name();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int _PushString(const char *string, int sz_flags, int cp_flags, size_t len);
|
||||||
|
int SetError(int err);
|
||||||
|
|
||||||
|
private:
|
||||||
|
IPluginContext *context_;
|
||||||
|
cell_t m_params[SP_MAX_EXEC_PARAMS];
|
||||||
|
ParamInfo m_info[SP_MAX_EXEC_PARAMS];
|
||||||
|
unsigned int m_curparam;
|
||||||
|
int m_errorstate;
|
||||||
|
ke::RefPtr<Native> native_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //_INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_
|
@ -8,7 +8,7 @@
|
|||||||
* This program is free software; you can redistribute it and/or modify it under
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||||
* Free Software Foundation.
|
* Free Software Foundation.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
@ -36,6 +36,9 @@
|
|||||||
#include <IHandleSys.h>
|
#include <IHandleSys.h>
|
||||||
#include <IForwardSys.h>
|
#include <IForwardSys.h>
|
||||||
#include <ISourceMod.h>
|
#include <ISourceMod.h>
|
||||||
|
#include <amtl/am-autoptr.h>
|
||||||
|
#include "ShareSys.h"
|
||||||
|
#include "NativeInvoker.h"
|
||||||
|
|
||||||
HandleType_t g_GlobalFwdType = 0;
|
HandleType_t g_GlobalFwdType = 0;
|
||||||
HandleType_t g_PrivateFwdType = 0;
|
HandleType_t g_PrivateFwdType = 0;
|
||||||
@ -44,8 +47,9 @@ static bool s_CallStarted = false;
|
|||||||
static ICallable *s_pCallable = NULL;
|
static ICallable *s_pCallable = NULL;
|
||||||
static IPluginFunction *s_pFunction = NULL;
|
static IPluginFunction *s_pFunction = NULL;
|
||||||
static IForward *s_pForward = NULL;
|
static IForward *s_pForward = NULL;
|
||||||
|
static NativeInvoker *s_pInvoker = NULL;
|
||||||
|
|
||||||
class ForwardNativeHelpers :
|
class ForwardNativeHelpers :
|
||||||
public SMGlobalClass,
|
public SMGlobalClass,
|
||||||
public IHandleTypeDispatch
|
public IHandleTypeDispatch
|
||||||
{
|
{
|
||||||
@ -103,6 +107,9 @@ inline void ResetCall()
|
|||||||
s_pFunction = NULL;
|
s_pFunction = NULL;
|
||||||
s_pForward = NULL;
|
s_pForward = NULL;
|
||||||
s_pCallable = NULL;
|
s_pCallable = NULL;
|
||||||
|
if(s_pInvoker)
|
||||||
|
delete s_pInvoker;
|
||||||
|
s_pInvoker = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static cell_t sm_GetFunctionByName(IPluginContext *pContext, const cell_t *params)
|
static cell_t sm_GetFunctionByName(IPluginContext *pContext, const cell_t *params)
|
||||||
@ -148,7 +155,7 @@ static cell_t sm_CreateGlobalForward(IPluginContext *pContext, const cell_t *par
|
|||||||
{
|
{
|
||||||
return pContext->ThrowNativeErrorEx(SP_ERROR_PARAMS_MAX, NULL);
|
return pContext->ThrowNativeErrorEx(SP_ERROR_PARAMS_MAX, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
pContext->LocalToString(params[1], &name);
|
pContext->LocalToString(params[1], &name);
|
||||||
|
|
||||||
cell_t *addr;
|
cell_t *addr;
|
||||||
@ -379,6 +386,27 @@ static cell_t sm_CallStartForward(IPluginContext *pContext, const cell_t *params
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static cell_t sm_CallStartNative(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
ResetCall();
|
||||||
|
|
||||||
|
char *name;
|
||||||
|
pContext->LocalToString(params[1], &name);
|
||||||
|
|
||||||
|
ke::RefPtr<Native> pNative = g_ShareSys.FindNative(name);
|
||||||
|
|
||||||
|
if (!pNative)
|
||||||
|
return 0;//pContext->ThrowNativeError("Invalid native \"%s\"", name);
|
||||||
|
|
||||||
|
s_pInvoker = new NativeInvoker(pContext, pNative);
|
||||||
|
|
||||||
|
s_pCallable = static_cast<ICallable *>(s_pInvoker);
|
||||||
|
|
||||||
|
s_CallStarted = true;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static cell_t sm_CallPushCell(IPluginContext *pContext, const cell_t *params)
|
static cell_t sm_CallPushCell(IPluginContext *pContext, const cell_t *params)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
@ -669,6 +697,39 @@ static cell_t sm_CallFinish(IPluginContext *pContext, const cell_t *params)
|
|||||||
IForward *pForward = s_pForward;
|
IForward *pForward = s_pForward;
|
||||||
ResetCall();
|
ResetCall();
|
||||||
err = pForward->Execute(result, NULL);
|
err = pForward->Execute(result, NULL);
|
||||||
|
} else if (s_pInvoker) {
|
||||||
|
err = s_pInvoker->Execute(result);
|
||||||
|
ResetCall();
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cell_t sm_CallFinishEx(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
int err = SP_ERROR_NOT_RUNNABLE;
|
||||||
|
cell_t *result;
|
||||||
|
|
||||||
|
if (!s_CallStarted)
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Cannot finish call when there is no call in progress");
|
||||||
|
}
|
||||||
|
|
||||||
|
pContext->LocalToPhysAddr(params[1], &result);
|
||||||
|
|
||||||
|
// Note: Execute() swallows exceptions, so this is okay.
|
||||||
|
if (s_pFunction)
|
||||||
|
{
|
||||||
|
IPluginFunction *pFunction = s_pFunction;
|
||||||
|
ResetCall();
|
||||||
|
err = pFunction->Execute(result, params[2], params[3]);
|
||||||
|
} else if (s_pForward) {
|
||||||
|
IForward *pForward = s_pForward;
|
||||||
|
ResetCall();
|
||||||
|
err = pForward->Execute(result, NULL);
|
||||||
|
} else if (s_pInvoker) {
|
||||||
|
err = s_pInvoker->Execute(result, params[2], params[3]);
|
||||||
|
ResetCall();
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
@ -755,6 +816,7 @@ REGISTER_NATIVES(functionNatives)
|
|||||||
{"RemoveAllFromForward", sm_RemoveAllFromForward},
|
{"RemoveAllFromForward", sm_RemoveAllFromForward},
|
||||||
{"Call_StartFunction", sm_CallStartFunction},
|
{"Call_StartFunction", sm_CallStartFunction},
|
||||||
{"Call_StartForward", sm_CallStartForward},
|
{"Call_StartForward", sm_CallStartForward},
|
||||||
|
{"Call_StartNative", sm_CallStartNative},
|
||||||
{"Call_PushCell", sm_CallPushCell},
|
{"Call_PushCell", sm_CallPushCell},
|
||||||
{"Call_PushCellRef", sm_CallPushCellRef},
|
{"Call_PushCellRef", sm_CallPushCellRef},
|
||||||
{"Call_PushFloat", sm_CallPushFloat},
|
{"Call_PushFloat", sm_CallPushFloat},
|
||||||
@ -766,6 +828,7 @@ REGISTER_NATIVES(functionNatives)
|
|||||||
{"Call_PushNullVector", sm_CallPushNullVector},
|
{"Call_PushNullVector", sm_CallPushNullVector},
|
||||||
{"Call_PushNullString", sm_CallPushNullString},
|
{"Call_PushNullString", sm_CallPushNullString},
|
||||||
{"Call_Finish", sm_CallFinish},
|
{"Call_Finish", sm_CallFinish},
|
||||||
|
{"Call_FinishEx", sm_CallFinishEx},
|
||||||
{"Call_Cancel", sm_CallCancel},
|
{"Call_Cancel", sm_CallCancel},
|
||||||
{"RequestFrame", sm_AddFrameAction},
|
{"RequestFrame", sm_AddFrameAction},
|
||||||
|
|
||||||
|
@ -293,6 +293,17 @@ native void Call_StartForward(Handle fwd);
|
|||||||
*/
|
*/
|
||||||
native void Call_StartFunction(Handle plugin, Function func);
|
native void Call_StartFunction(Handle plugin, Function func);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a call to a native.
|
||||||
|
*
|
||||||
|
* @note Cannot be used during an incomplete call.
|
||||||
|
*
|
||||||
|
* @param name Name of the native.
|
||||||
|
* @return True on success, false otherwise.
|
||||||
|
* @error Invalid function, or called before another call has completed.
|
||||||
|
*/
|
||||||
|
native bool Call_StartNative(const char[] name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pushes a cell onto the current call.
|
* Pushes a cell onto the current call.
|
||||||
*
|
*
|
||||||
@ -416,6 +427,20 @@ native void Call_PushNullString();
|
|||||||
*/
|
*/
|
||||||
native int Call_Finish(any &result=0);
|
native int Call_Finish(any &result=0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Completes a call to a function or forward's call list.
|
||||||
|
* Catches exceptions thrown by the native.
|
||||||
|
*
|
||||||
|
* @note Cannot be used before a call has been started.
|
||||||
|
*
|
||||||
|
* @param result Return value of function or forward's call list.
|
||||||
|
* @param exception Buffer to store the exception in.
|
||||||
|
* @param maxlength Maximum length of the buffer.
|
||||||
|
* @return SP_ERROR_NONE on success, any other integer on failure.
|
||||||
|
* @error Called before a call has been started.
|
||||||
|
*/
|
||||||
|
native int Call_FinishEx(any &result=0, char[] exception, int maxlength);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancels a call to a function or forward's call list.
|
* Cancels a call to a function or forward's call list.
|
||||||
*
|
*
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit d59a51b5741823903ecbe8c014632ee1f8aad65d
|
Subproject commit 04eafd88631e7a3ba1de6bc7228af0e3d5443f0b
|
Loading…
Reference in New Issue
Block a user