1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/core/systems/CFunction.cpp Sat Nov 11 11:10:24 2006 +0000
1.3 @@ -0,0 +1,272 @@
1.4 +#include <stdio.h>
1.5 +#include "PluginSys.h"
1.6 +
1.7 +/********************
1.8 +* FUNCTION CALLING *
1.9 +********************/
1.10 +
1.11 +void CFunction::Set(funcid_t funcid, CPlugin *plugin)
1.12 +{
1.13 + m_funcid = funcid;
1.14 + m_pPlugin = plugin;
1.15 + m_curparam = 0;
1.16 + m_errorstate = SP_ERROR_NONE;
1.17 +}
1.18 +
1.19 +int CFunction::CallFunction(const cell_t *params, unsigned int num_params, cell_t *result)
1.20 +{
1.21 + IPluginContext *ctx = m_pPlugin->m_ctx_current.base;
1.22 +
1.23 + while (num_params--)
1.24 + {
1.25 + ctx->PushCell(params[num_params]);
1.26 + }
1.27 +
1.28 + return ctx->Execute(m_funcid, result);
1.29 +}
1.30 +
1.31 +IPlugin *CFunction::GetParentPlugin()
1.32 +{
1.33 + return m_pPlugin;
1.34 +}
1.35 +
1.36 +CFunction::CFunction(funcid_t funcid, CPlugin *plugin) :
1.37 + m_funcid(funcid), m_pPlugin(plugin), m_curparam(0),
1.38 + m_errorstate(SP_ERROR_NONE)
1.39 +{
1.40 +}
1.41 +
1.42 +int CFunction::PushCell(cell_t cell)
1.43 +{
1.44 + if (m_curparam >= SP_MAX_EXEC_PARAMS)
1.45 + {
1.46 + return SetError(SP_ERROR_PARAMS_MAX);
1.47 + }
1.48 +
1.49 + m_info[m_curparam].marked = false;
1.50 + m_params[m_curparam] = cell;
1.51 + m_curparam++;
1.52 +
1.53 + return SP_ERROR_NONE;
1.54 +}
1.55 +
1.56 +int CFunction::PushCellByRef(cell_t *cell, int flags)
1.57 +{
1.58 + if (m_curparam >= SP_MAX_EXEC_PARAMS)
1.59 + {
1.60 + return SetError(SP_ERROR_PARAMS_MAX);
1.61 + }
1.62 +
1.63 + return PushArray(cell, 1, NULL, flags);
1.64 +}
1.65 +
1.66 +int CFunction::PushFloat(float number)
1.67 +{
1.68 + cell_t val = *(cell_t *)&number;
1.69 +
1.70 + return PushCell(val);
1.71 +}
1.72 +
1.73 +int CFunction::PushFloatByRef(float *number, int flags)
1.74 +{
1.75 + return PushCellByRef((cell_t *)number, flags);
1.76 +}
1.77 +
1.78 +int CFunction::PushCells(cell_t array[], unsigned int numcells, bool each)
1.79 +{
1.80 + if (!each)
1.81 + {
1.82 + return PushArray(array, numcells, NULL, SMFUNC_COPYBACK_NONE);
1.83 + } else {
1.84 + int err;
1.85 + for (unsigned int i=0; i<numcells; i++)
1.86 + {
1.87 + if ((err=PushCell(array[i])) != SP_ERROR_NONE)
1.88 + {
1.89 + return SetError(err);
1.90 + }
1.91 + }
1.92 + return SP_ERROR_NONE;
1.93 + }
1.94 +}
1.95 +
1.96 +int CFunction::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int copyback)
1.97 +{
1.98 + if (m_curparam >= SP_MAX_EXEC_PARAMS)
1.99 + {
1.100 + return SetError(SP_ERROR_PARAMS_MAX);
1.101 + }
1.102 +
1.103 + IPluginContext *ctx = m_pPlugin->m_ctx_current.base;
1.104 + ParamInfo *info = &m_info[m_curparam];
1.105 + int err;
1.106 +
1.107 + if ((err=ctx->HeapAlloc(cells, &info->local_addr, &info->phys_addr)) != SP_ERROR_NONE)
1.108 + {
1.109 + return SetError(err);
1.110 + }
1.111 +
1.112 + info->flags = inarray ? copyback : SMFUNC_COPYBACK_NONE;
1.113 + info->marked = true;
1.114 + info->size = cells;
1.115 + m_params[m_curparam] = info->local_addr;
1.116 + m_curparam++;
1.117 +
1.118 + if (inarray)
1.119 + {
1.120 + memcpy(info->phys_addr, inarray, sizeof(cell_t) * cells);
1.121 + info->orig_addr = inarray;
1.122 + } else {
1.123 + info->orig_addr = info->phys_addr;
1.124 + }
1.125 +
1.126 + if (phys_addr)
1.127 + {
1.128 + *phys_addr = info->phys_addr;
1.129 + }
1.130 +
1.131 + return true;
1.132 +}
1.133 +
1.134 +int CFunction::PushString(const char *string)
1.135 +{
1.136 + return _PushString(string, SMFUNC_COPYBACK_NONE);
1.137 +}
1.138 +
1.139 +int CFunction::PushStringByRef(char *string, int flags)
1.140 +{
1.141 + return _PushString(string, flags);
1.142 +}
1.143 +
1.144 +int CFunction::_PushString(const char *string, int flags)
1.145 +{
1.146 + if (m_curparam >= SP_MAX_EXEC_PARAMS)
1.147 + {
1.148 + return SetError(SP_ERROR_PARAMS_MAX);
1.149 + }
1.150 +
1.151 + IPluginContext *base = m_pPlugin->m_ctx_current.base;
1.152 + ParamInfo *info = &m_info[m_curparam];
1.153 + size_t len = strlen(string);
1.154 + size_t cells = (len + sizeof(cell_t) - 1) / sizeof(cell_t);
1.155 + int err;
1.156 +
1.157 + if ((err=base->HeapAlloc(cells, &info->local_addr, &info->phys_addr)) != SP_ERROR_NONE)
1.158 + {
1.159 + return SetError(err);
1.160 + }
1.161 +
1.162 + info->marked = true;
1.163 + m_params[m_curparam] = info->local_addr;
1.164 + m_curparam++; /* Prevent a leak */
1.165 +
1.166 + //:TODO: Use UTF-8 version
1.167 + if ((err=base->StringToLocal(info->local_addr, len, string)) != SP_ERROR_NONE)
1.168 + {
1.169 + return SetError(err);
1.170 + }
1.171 +
1.172 + info->flags = flags;
1.173 + info->orig_addr = (cell_t *)string;
1.174 + info->size = cells;
1.175 +
1.176 + return SP_ERROR_NONE;
1.177 +}
1.178 +
1.179 +void CFunction::Cancel()
1.180 +{
1.181 + if (!m_curparam)
1.182 + {
1.183 + return;
1.184 + }
1.185 +
1.186 + IPluginContext *base = m_pPlugin->m_ctx_current.base;
1.187 +
1.188 + while (m_curparam--)
1.189 + {
1.190 + if (m_info[m_curparam].marked)
1.191 + {
1.192 + base->HeapRelease(m_info[m_curparam].local_addr);
1.193 + m_info[m_curparam].marked = false;
1.194 + }
1.195 + }
1.196 +
1.197 + m_errorstate = SP_ERROR_NONE;
1.198 +}
1.199 +
1.200 +int CFunction::Execute(cell_t *result, IFunctionCopybackReader *reader)
1.201 +{
1.202 + int err;
1.203 + if (m_errorstate != SP_ERROR_NONE)
1.204 + {
1.205 + err = m_errorstate;
1.206 + Cancel();
1.207 + return err;
1.208 + }
1.209 +
1.210 + //This is for re-entrancy!
1.211 + cell_t temp_params[SP_MAX_EXEC_PARAMS];
1.212 + ParamInfo temp_info[SP_MAX_EXEC_PARAMS];
1.213 + unsigned int numparams = m_curparam;
1.214 + bool docopies = true;
1.215 +
1.216 + if (numparams)
1.217 + {
1.218 + //Save the info locally, then reset it for re-entrant calls.
1.219 + memcpy(temp_params, m_params, numparams * sizeof(cell_t));
1.220 + memcpy(temp_info, m_info, numparams * sizeof(ParamInfo));
1.221 + }
1.222 + m_curparam = 0;
1.223 +
1.224 + if ((err = CallFunction(temp_params, numparams, result)) != SP_ERROR_NONE)
1.225 + {
1.226 + docopies = false;
1.227 + }
1.228 +
1.229 + IPluginContext *base = m_pPlugin->m_ctx_current.base;
1.230 +
1.231 + while (numparams--)
1.232 + {
1.233 + if (!temp_info[numparams].marked)
1.234 + {
1.235 + continue;
1.236 + }
1.237 + if (docopies && temp_info[numparams].flags)
1.238 + {
1.239 + if (reader)
1.240 + {
1.241 + if (!reader->OnCopybackArray(numparams,
1.242 + temp_info[numparams].size,
1.243 + temp_info[numparams].phys_addr,
1.244 + temp_info[numparams].orig_addr,
1.245 + temp_info[numparams].flags))
1.246 + {
1.247 + goto _skipcopy;
1.248 + }
1.249 + }
1.250 + if (temp_info[numparams].orig_addr)
1.251 + {
1.252 + memcpy(temp_info[numparams].orig_addr,
1.253 + temp_info[numparams].phys_addr,
1.254 + temp_info[numparams].size * sizeof(cell_t));
1.255 + }
1.256 + }
1.257 +_skipcopy:
1.258 + base->HeapRelease(temp_info[numparams].local_addr);
1.259 + temp_info[numparams].marked = false;
1.260 + }
1.261 +
1.262 + return err;
1.263 +}
1.264 +
1.265 +cell_t *CFunction::GetAddressOfPushedParam(unsigned int param)
1.266 +{
1.267 + if (m_errorstate != SP_ERROR_NONE
1.268 + || param >= m_curparam
1.269 + || !m_info[param].marked)
1.270 + {
1.271 + return NULL;
1.272 + }
1.273 +
1.274 + return m_info[param].phys_addr;
1.275 +}