sourcemod/core/systems/CFunction.cpp
Borja Ferrer f3ad0f5b67 rewritten PushStringEx in Forward and Function systems
fixed PushCellByRef and PushFloatByRef in the varargs case where it wouldn't set the pushed type
fixed the BindNatives functions not setting the BOUND flag thus making the JIT not exec the natives
done the rest of tests with forwards, only left to do string varargs

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40197
2006-12-06 14:52:11 +00:00

260 lines
5.4 KiB
C++

#include <stdio.h>
#include "PluginSys.h"
/********************
* FUNCTION CALLING *
********************/
void CFunction::Set(funcid_t funcid, CPlugin *plugin)
{
m_funcid = funcid;
m_pPlugin = plugin;
m_curparam = 0;
m_errorstate = SP_ERROR_NONE;
}
int CFunction::CallFunction(const cell_t *params, unsigned int num_params, cell_t *result)
{
IPluginContext *ctx = m_pPlugin->m_ctx_current.base;
while (num_params--)
{
ctx->PushCell(params[num_params]);
}
return ctx->Execute(m_funcid, result);
}
IPlugin *CFunction::GetParentPlugin()
{
return m_pPlugin;
}
CFunction::CFunction(funcid_t funcid, CPlugin *plugin) :
m_funcid(funcid), m_pPlugin(plugin), m_curparam(0),
m_errorstate(SP_ERROR_NONE)
{
}
int CFunction::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 CFunction::PushCellByRef(cell_t *cell, int flags)
{
if (m_curparam >= SP_MAX_EXEC_PARAMS)
{
return SetError(SP_ERROR_PARAMS_MAX);
}
return PushArray(cell, 1, NULL, flags);
}
int CFunction::PushFloat(float number)
{
cell_t val = *(cell_t *)&number;
return PushCell(val);
}
int CFunction::PushFloatByRef(float *number, int flags)
{
return PushCellByRef((cell_t *)number, flags);
}
int CFunction::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int copyback)
{
if (m_curparam >= SP_MAX_EXEC_PARAMS)
{
return SetError(SP_ERROR_PARAMS_MAX);
}
IPluginContext *ctx = m_pPlugin->m_ctx_current.base;
ParamInfo *info = &m_info[m_curparam];
int err;
if ((err=ctx->HeapAlloc(cells, &info->local_addr, &info->phys_addr)) != SP_ERROR_NONE)
{
return SetError(err);
}
info->flags = inarray ? copyback : 0;
info->marked = true;
info->size = cells;
m_params[m_curparam] = info->local_addr;
m_curparam++;
if (inarray)
{
memcpy(info->phys_addr, inarray, sizeof(cell_t) * cells);
info->orig_addr = inarray;
} else {
info->orig_addr = info->phys_addr;
}
if (phys_addr)
{
*phys_addr = info->phys_addr;
}
return true;
}
int CFunction::PushString(const char *string)
{
return _PushString(string, SP_STRING_COPY, 0, strlen(string)+1);
}
int CFunction::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
{
return _PushString(buffer, sz_flags, cp_flags, length);
}
int CFunction::_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);
}
IPluginContext *base = m_pPlugin->m_ctx_current.base;
ParamInfo *info = &m_info[m_curparam];
size_t cells = (len + sizeof(cell_t) - 1) / sizeof(cell_t);
int err;
if ((err=base->HeapAlloc(cells, &info->local_addr, &info->phys_addr)) != SP_ERROR_NONE)
{
return SetError(err);
}
info->marked = true;
m_params[m_curparam] = info->local_addr;
m_curparam++; /* Prevent a leak */
if (!(sz_flags & SP_STRING_COPY))
{
goto skip_localtostr;
}
if (sz_flags & SP_STRING_UTF8)
{
if ((err=base->StringToLocalUTF8(info->local_addr, len, string, NULL)) != SP_ERROR_NONE)
{
return SetError(err);
}
} else {
if ((err=base->StringToLocal(info->local_addr, len, string)) != SP_ERROR_NONE)
{
return SetError(err);
}
}
skip_localtostr:
info->flags = cp_flags;
info->orig_addr = (cell_t *)string;
info->size = cells;
return SP_ERROR_NONE;
}
void CFunction::Cancel()
{
if (!m_curparam)
{
return;
}
IPluginContext *base = m_pPlugin->m_ctx_current.base;
while (m_curparam--)
{
if (m_info[m_curparam].marked)
{
base->HeapRelease(m_info[m_curparam].local_addr);
m_info[m_curparam].marked = false;
}
}
m_errorstate = SP_ERROR_NONE;
}
int CFunction::Execute(cell_t *result)
{
int err;
if (m_errorstate != SP_ERROR_NONE)
{
err = m_errorstate;
Cancel();
return err;
}
//This is for re-entrancy!
cell_t temp_params[SP_MAX_EXEC_PARAMS];
ParamInfo temp_info[SP_MAX_EXEC_PARAMS];
unsigned int numparams = m_curparam;
bool docopies = true;
if (numparams)
{
//Save the info locally, then reset it for re-entrant calls.
memcpy(temp_params, m_params, numparams * sizeof(cell_t));
memcpy(temp_info, m_info, numparams * sizeof(ParamInfo));
}
m_curparam = 0;
if ((err = CallFunction(temp_params, numparams, result)) != SP_ERROR_NONE)
{
docopies = false;
}
IPluginContext *base = m_pPlugin->m_ctx_current.base;
while (numparams--)
{
if (!temp_info[numparams].marked)
{
continue;
}
if (docopies && temp_info[numparams].flags)
{
if (temp_info[numparams].orig_addr)
{
if (temp_info[numparams].size == 1)
{
*temp_info[numparams].orig_addr = *temp_info[numparams].phys_addr;
} else {
memcpy(temp_info[numparams].orig_addr,
temp_info[numparams].phys_addr,
temp_info[numparams].size * sizeof(cell_t));
}
}
}
base->HeapPop(temp_info[numparams].local_addr);
temp_info[numparams].marked = false;
}
return err;
}
cell_t *CFunction::GetAddressOfPushedParam(unsigned int param)
{
if (m_errorstate != SP_ERROR_NONE
|| param >= m_curparam
|| !m_info[param].marked)
{
return NULL;
}
return m_info[param].phys_addr;
}