core/systems/CFunction.cpp
author David Anderson <dvander@alliedmods.net>
Sun Nov 12 09:51:39 2006 +0000 (2006-11-12)
changeset 183 78488edd8873
parent 181 1e1570518051
child 185 5e0987d38ee0
permissions -rw-r--r--
rewrote forward API to use cached parameter pushing instead of immediate pushing
removed copy back cruft since it's no longer needed
removed PushCells() from API requirements, not needed
adjusted documentation and added TODO list to ForwardSys.cpp
various internal improvements
     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, 0);
    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 : 0;
   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 		memcpy(info->phys_addr, inarray, sizeof(cell_t) * cells);
   118 		info->orig_addr = inarray;
   119 	} else {
   120 		info->orig_addr = info->phys_addr;
   121 	}
   122 
   123 	if (phys_addr)
   124 	{
   125 		*phys_addr = info->phys_addr;
   126 	}
   127 
   128 	return true;
   129 }
   130 
   131 int CFunction::PushString(const char *string)
   132 {
   133 	return _PushString(string, 0);
   134 }
   135 
   136 int CFunction::PushStringEx(char *string, int flags)
   137 {
   138 	return _PushString(string, flags);
   139 }
   140 
   141 int CFunction::_PushString(const char *string, int flags)
   142 {
   143 	if (m_curparam >= SP_MAX_EXEC_PARAMS)
   144 	{
   145 		return SetError(SP_ERROR_PARAMS_MAX);
   146 	}
   147 
   148 	IPluginContext *base = m_pPlugin->m_ctx_current.base;
   149 	ParamInfo *info = &m_info[m_curparam];
   150 	size_t len = strlen(string);
   151 	size_t cells = (len + sizeof(cell_t) - 1) / sizeof(cell_t);
   152 	int err;
   153 
   154 	if ((err=base->HeapAlloc(cells, &info->local_addr, &info->phys_addr)) != SP_ERROR_NONE)
   155 	{
   156 		return SetError(err);
   157 	}
   158 
   159 	info->marked = true;
   160 	m_params[m_curparam] = info->local_addr;
   161 	m_curparam++;	/* Prevent a leak */
   162 
   163 	if ((err=base->StringToLocalUTF8(info->local_addr, len, string, NULL)) != SP_ERROR_NONE)
   164 	{
   165 		return SetError(err);
   166 	}
   167 
   168 	info->flags = flags;
   169 	info->orig_addr = (cell_t *)string;
   170 	info->size = cells;
   171 
   172 	return SP_ERROR_NONE;
   173 }
   174 
   175 void CFunction::Cancel()
   176 {
   177 	if (!m_curparam)
   178 	{
   179 		return;
   180 	}
   181 
   182 	IPluginContext *base = m_pPlugin->m_ctx_current.base;
   183 
   184 	while (m_curparam--)
   185 	{
   186 		if (m_info[m_curparam].marked)
   187 		{
   188 			base->HeapRelease(m_info[m_curparam].local_addr);
   189 			m_info[m_curparam].marked = false;
   190 		}
   191 	}
   192 
   193 	m_errorstate = SP_ERROR_NONE;
   194 }
   195 
   196 int CFunction::Execute(cell_t *result)
   197 {
   198 	int err;
   199 	if (m_errorstate != SP_ERROR_NONE)
   200 	{
   201 		err = m_errorstate;
   202 		Cancel();
   203 		return err;
   204 	}
   205 
   206 	//This is for re-entrancy!
   207 	cell_t temp_params[SP_MAX_EXEC_PARAMS];
   208 	ParamInfo temp_info[SP_MAX_EXEC_PARAMS];
   209 	unsigned int numparams = m_curparam;
   210 	bool docopies = true;
   211 
   212 	if (numparams)
   213 	{
   214 		//Save the info locally, then reset it for re-entrant calls.
   215 		memcpy(temp_params, m_params, numparams * sizeof(cell_t));
   216 		memcpy(temp_info, m_info, numparams * sizeof(ParamInfo));
   217 	}
   218 	m_curparam = 0;
   219 
   220 	if ((err = CallFunction(temp_params, numparams, result)) != SP_ERROR_NONE)
   221 	{
   222 		docopies = false;
   223 	}
   224 
   225 	IPluginContext *base = m_pPlugin->m_ctx_current.base;
   226 
   227 	while (numparams--)
   228 	{
   229 		if (!temp_info[numparams].marked)
   230 		{
   231 			continue;
   232 		}
   233 		if (docopies && temp_info[numparams].flags)
   234 		{
   235 			if (temp_info[numparams].orig_addr)
   236 			{
   237 				if (temp_info[numparams].size == 1)
   238 				{
   239 					*temp_info[numparams].orig_addr = *temp_info[numparams].phys_addr;
   240 				} else {
   241 					memcpy(temp_info[numparams].orig_addr, 
   242 							temp_info[numparams].phys_addr, 
   243 							temp_info[numparams].size * sizeof(cell_t));
   244 				}
   245 			}
   246 		}
   247 		base->HeapPop(temp_info[numparams].local_addr);
   248 		temp_info[numparams].marked = false;
   249 	}
   250 
   251 	return err;
   252 }
   253 
   254 cell_t *CFunction::GetAddressOfPushedParam(unsigned int param)
   255 {
   256 	if (m_errorstate != SP_ERROR_NONE
   257 		|| param >= m_curparam
   258 		|| !m_info[param].marked)
   259 	{
   260 		return NULL;
   261 	}
   262 
   263 	return m_info[param].phys_addr;
   264 }