core/systems/CFunction.cpp
author David Anderson <dvander@alliedmods.net>
Sun Nov 12 02:24:45 2006 +0000 (2006-11-12)
changeset 181 1e1570518051
parent 180 fe406c5f2aeb
child 183 78488edd8873
permissions -rw-r--r--
fixed copy backs so they work properly
NOTE: heap fails, working on a rewrite
     1 #include <stdio.h>
     2 #include "PluginSys.h"
     3 
     4 /********************
     5 * FUNCTION CALLING *
     6 ********************/
     7 
     8 void CFunction::Set(funcid_t funcid, CPlugin *plugin)
     9 {
    10 	m_funcid = funcid;
    11 	m_pPlugin = plugin;
    12 	m_curparam = 0;
    13 	m_errorstate = SP_ERROR_NONE;
    14 }
    15 
    16 int CFunction::CallFunction(const cell_t *params, unsigned int num_params, cell_t *result)
    17 {
    18 	IPluginContext *ctx = m_pPlugin->m_ctx_current.base;
    19 
    20 	while (num_params--)
    21 	{
    22 		ctx->PushCell(params[num_params]);
    23 	}
    24 
    25 	return ctx->Execute(m_funcid, result);
    26 }
    27 
    28 IPlugin *CFunction::GetParentPlugin()
    29 {
    30 	return m_pPlugin;
    31 }
    32 
    33 CFunction::CFunction(funcid_t funcid, CPlugin *plugin) : 
    34 	m_funcid(funcid), m_pPlugin(plugin), m_curparam(0), 
    35 	m_errorstate(SP_ERROR_NONE)
    36 {
    37 }
    38 
    39 int CFunction::PushCell(cell_t cell)
    40 {
    41 	if (m_curparam >= SP_MAX_EXEC_PARAMS)
    42 	{
    43 		return SetError(SP_ERROR_PARAMS_MAX);
    44 	}
    45 
    46 	m_info[m_curparam].marked = false;
    47 	m_params[m_curparam] = cell;
    48 	m_curparam++;
    49 
    50 	return SP_ERROR_NONE;
    51 }
    52 
    53 int CFunction::PushCellByRef(cell_t *cell, int flags)
    54 {
    55 	if (m_curparam >= SP_MAX_EXEC_PARAMS)
    56 	{
    57 		return SetError(SP_ERROR_PARAMS_MAX);
    58 	}
    59 
    60 	return PushArray(cell, 1, NULL, flags);
    61 }
    62 
    63 int CFunction::PushFloat(float number)
    64 {
    65 	cell_t val = *(cell_t *)&number;
    66 
    67 	return PushCell(val);
    68 }
    69 
    70 int CFunction::PushFloatByRef(float *number, int flags)
    71 {
    72 	return PushCellByRef((cell_t *)number, flags);
    73 }
    74 
    75 int CFunction::PushCells(cell_t array[], unsigned int numcells, bool each)
    76 {
    77 	if (!each)
    78 	{
    79 		return PushArray(array, numcells, NULL, SMFUNC_COPYBACK_NONE);
    80 	} else {
    81 		int err;
    82 		for (unsigned int i=0; i<numcells; i++)
    83 		{
    84 			if ((err=PushCell(array[i])) != SP_ERROR_NONE)
    85 			{
    86 				return SetError(err);
    87 			}
    88 		}
    89 		return SP_ERROR_NONE;
    90 	}
    91 }
    92 
    93 int CFunction::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int copyback)
    94 {
    95 	if (m_curparam >= SP_MAX_EXEC_PARAMS)
    96 	{
    97 		return SetError(SP_ERROR_PARAMS_MAX);
    98 	}
    99 
   100 	IPluginContext *ctx = m_pPlugin->m_ctx_current.base;
   101 	ParamInfo *info = &m_info[m_curparam];
   102 	int err;
   103 
   104 	if ((err=ctx->HeapAlloc(cells, &info->local_addr, &info->phys_addr)) != SP_ERROR_NONE)
   105 	{
   106 		return SetError(err);
   107 	}
   108 
   109 	info->flags = (inarray || (copyback & SMFUNC_COPYBACK_ALWAYS)) ? copyback : SMFUNC_COPYBACK_NONE;
   110 	info->marked = true;
   111 	info->size = cells;
   112 	m_params[m_curparam] = info->local_addr;
   113 	m_curparam++;
   114 
   115 	if (inarray)
   116 	{
   117 		if (!(copyback & SMFUNC_ARRAY_NOINIT))
   118 		{
   119 			memcpy(info->phys_addr, inarray, sizeof(cell_t) * cells);
   120 		}
   121 		info->orig_addr = inarray;
   122 	} else {
   123 		info->orig_addr = info->phys_addr;
   124 	}
   125 
   126 	if (phys_addr)
   127 	{
   128 		*phys_addr = info->phys_addr;
   129 	}
   130 
   131 	return true;
   132 }
   133 
   134 int CFunction::PushString(const char *string)
   135 {
   136 	return _PushString(string, SMFUNC_COPYBACK_NONE);
   137 }
   138 
   139 int CFunction::PushStringByRef(char *string, int flags)
   140 {
   141 	return _PushString(string, flags);
   142 }
   143 
   144 int CFunction::_PushString(const char *string, int flags)
   145 {
   146 	if (m_curparam >= SP_MAX_EXEC_PARAMS)
   147 	{
   148 		return SetError(SP_ERROR_PARAMS_MAX);
   149 	}
   150 
   151 	IPluginContext *base = m_pPlugin->m_ctx_current.base;
   152 	ParamInfo *info = &m_info[m_curparam];
   153 	size_t len = strlen(string);
   154 	size_t cells = (len + sizeof(cell_t) - 1) / sizeof(cell_t);
   155 	int err;
   156 
   157 	if ((err=base->HeapAlloc(cells, &info->local_addr, &info->phys_addr)) != SP_ERROR_NONE)
   158 	{
   159 		return SetError(err);
   160 	}
   161 
   162 	info->marked = true;
   163 	m_params[m_curparam] = info->local_addr;
   164 	m_curparam++;	/* Prevent a leak */
   165 
   166 	//:TODO: Use UTF-8 version
   167 	if ((err=base->StringToLocal(info->local_addr, len, string)) != SP_ERROR_NONE)
   168 	{
   169 		return SetError(err);
   170 	}
   171 
   172 	info->flags = flags;
   173 	info->orig_addr = (cell_t *)string;
   174 	info->size = cells;
   175 
   176 	return SP_ERROR_NONE;
   177 }
   178 
   179 void CFunction::Cancel()
   180 {
   181 	if (!m_curparam)
   182 	{
   183 		return;
   184 	}
   185 
   186 	IPluginContext *base = m_pPlugin->m_ctx_current.base;
   187 
   188 	while (m_curparam--)
   189 	{
   190 		if (m_info[m_curparam].marked)
   191 		{
   192 			base->HeapRelease(m_info[m_curparam].local_addr);
   193 			m_info[m_curparam].marked = false;
   194 		}
   195 	}
   196 
   197 	m_errorstate = SP_ERROR_NONE;
   198 }
   199 
   200 int CFunction::Execute(cell_t *result, IFunctionCopybackReader *reader)
   201 {
   202 	int err;
   203 	if (m_errorstate != SP_ERROR_NONE)
   204 	{
   205 		err = m_errorstate;
   206 		Cancel();
   207 		return err;
   208 	}
   209 
   210 	//This is for re-entrancy!
   211 	cell_t temp_params[SP_MAX_EXEC_PARAMS];
   212 	ParamInfo temp_info[SP_MAX_EXEC_PARAMS];
   213 	unsigned int numparams = m_curparam;
   214 	bool docopies = true;
   215 
   216 	if (numparams)
   217 	{
   218 		//Save the info locally, then reset it for re-entrant calls.
   219 		memcpy(temp_params, m_params, numparams * sizeof(cell_t));
   220 		memcpy(temp_info, m_info, numparams * sizeof(ParamInfo));
   221 	}
   222 	m_curparam = 0;
   223 
   224 	if ((err = CallFunction(temp_params, numparams, result)) != SP_ERROR_NONE)
   225 	{
   226 		docopies = false;
   227 	}
   228 
   229 	IPluginContext *base = m_pPlugin->m_ctx_current.base;
   230 
   231 	while (numparams--)
   232 	{
   233 		if (!temp_info[numparams].marked)
   234 		{
   235 			continue;
   236 		}
   237 		if (docopies && temp_info[numparams].flags)
   238 		{
   239 			if (reader)
   240 			{
   241 				if (!reader->OnCopybackArray(numparams, 
   242 										temp_info[numparams].size, 
   243 										temp_info[numparams].phys_addr,
   244 										temp_info[numparams].orig_addr,
   245 										temp_info[numparams].flags))
   246 				{
   247 					goto _skipcopy;
   248 				}
   249 			}
   250 			if (temp_info[numparams].orig_addr)
   251 			{
   252 				if (temp_info[numparams].size == 1)
   253 				{
   254 					*temp_info[numparams].orig_addr = *temp_info[numparams].phys_addr;
   255 				} else {
   256 					memcpy(temp_info[numparams].orig_addr, 
   257 							temp_info[numparams].phys_addr, 
   258 							temp_info[numparams].size * sizeof(cell_t));
   259 				}
   260 			}
   261 		}
   262 _skipcopy:
   263 		base->HeapPop(temp_info[numparams].local_addr);
   264 		temp_info[numparams].marked = false;
   265 	}
   266 
   267 	return err;
   268 }
   269 
   270 cell_t *CFunction::GetAddressOfPushedParam(unsigned int param)
   271 {
   272 	if (m_errorstate != SP_ERROR_NONE
   273 		|| param >= m_curparam
   274 		|| !m_info[param].marked)
   275 	{
   276 		return NULL;
   277 	}
   278 
   279 	return m_info[param].phys_addr;
   280 }