core/systems/CFunction.cpp
author Borja Ferrer <faluco@alliedmods.net>
Fri Nov 17 23:22:32 2006 +0000 (2006-11-17)
changeset 188 8951baf7cb3c
parent 185 5e0987d38ee0
child 192 dee91851dcd4
permissions -rw-r--r--
fixed string pushing
fixed CFunction::_PushString not counting the null terminator
     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::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int copyback)
    76 {
    77 	if (m_curparam >= SP_MAX_EXEC_PARAMS)
    78 	{
    79 		return SetError(SP_ERROR_PARAMS_MAX);
    80 	}
    81 
    82 	IPluginContext *ctx = m_pPlugin->m_ctx_current.base;
    83 	ParamInfo *info = &m_info[m_curparam];
    84 	int err;
    85 
    86 	if ((err=ctx->HeapAlloc(cells, &info->local_addr, &info->phys_addr)) != SP_ERROR_NONE)
    87 	{
    88 		return SetError(err);
    89 	}
    90 
    91 	info->flags = inarray ? copyback : 0;
    92 	info->marked = true;
    93 	info->size = cells;
    94 	m_params[m_curparam] = info->local_addr;
    95 	m_curparam++;
    96 
    97 	if (inarray)
    98 	{
    99 		memcpy(info->phys_addr, inarray, sizeof(cell_t) * cells);
   100 		info->orig_addr = inarray;
   101 	} else {
   102 		info->orig_addr = info->phys_addr;
   103 	}
   104 
   105 	if (phys_addr)
   106 	{
   107 		*phys_addr = info->phys_addr;
   108 	}
   109 
   110 	return true;
   111 }
   112 
   113 int CFunction::PushString(const char *string)
   114 {
   115 	return _PushString(string, 0);
   116 }
   117 
   118 int CFunction::PushStringEx(char *string, int flags)
   119 {
   120 	return _PushString(string, flags);
   121 }
   122 
   123 int CFunction::_PushString(const char *string, int flags)
   124 {
   125 	if (m_curparam >= SP_MAX_EXEC_PARAMS)
   126 	{
   127 		return SetError(SP_ERROR_PARAMS_MAX);
   128 	}
   129 
   130 	IPluginContext *base = m_pPlugin->m_ctx_current.base;
   131 	ParamInfo *info = &m_info[m_curparam];
   132 	size_t len = strlen(string);
   133 	size_t cells = (len + sizeof(cell_t)) / sizeof(cell_t);
   134 	int err;
   135 
   136 	if ((err=base->HeapAlloc(cells, &info->local_addr, &info->phys_addr)) != SP_ERROR_NONE)
   137 	{
   138 		return SetError(err);
   139 	}
   140 
   141 	info->marked = true;
   142 	m_params[m_curparam] = info->local_addr;
   143 	m_curparam++;	/* Prevent a leak */
   144 
   145 	if ((err=base->StringToLocalUTF8(info->local_addr, len+1, string, NULL)) != SP_ERROR_NONE)
   146 	{
   147 		return SetError(err);
   148 	}
   149 
   150 	info->flags = flags;
   151 	info->orig_addr = (cell_t *)string;
   152 	info->size = cells;
   153 
   154 	return SP_ERROR_NONE;
   155 }
   156 
   157 void CFunction::Cancel()
   158 {
   159 	if (!m_curparam)
   160 	{
   161 		return;
   162 	}
   163 
   164 	IPluginContext *base = m_pPlugin->m_ctx_current.base;
   165 
   166 	while (m_curparam--)
   167 	{
   168 		if (m_info[m_curparam].marked)
   169 		{
   170 			base->HeapRelease(m_info[m_curparam].local_addr);
   171 			m_info[m_curparam].marked = false;
   172 		}
   173 	}
   174 
   175 	m_errorstate = SP_ERROR_NONE;
   176 }
   177 
   178 int CFunction::Execute(cell_t *result)
   179 {
   180 	int err;
   181 	if (m_errorstate != SP_ERROR_NONE)
   182 	{
   183 		err = m_errorstate;
   184 		Cancel();
   185 		return err;
   186 	}
   187 
   188 	//This is for re-entrancy!
   189 	cell_t temp_params[SP_MAX_EXEC_PARAMS];
   190 	ParamInfo temp_info[SP_MAX_EXEC_PARAMS];
   191 	unsigned int numparams = m_curparam;
   192 	bool docopies = true;
   193 
   194 	if (numparams)
   195 	{
   196 		//Save the info locally, then reset it for re-entrant calls.
   197 		memcpy(temp_params, m_params, numparams * sizeof(cell_t));
   198 		memcpy(temp_info, m_info, numparams * sizeof(ParamInfo));
   199 	}
   200 	m_curparam = 0;
   201 
   202 	if ((err = CallFunction(temp_params, numparams, result)) != SP_ERROR_NONE)
   203 	{
   204 		docopies = false;
   205 	}
   206 
   207 	IPluginContext *base = m_pPlugin->m_ctx_current.base;
   208 
   209 	while (numparams--)
   210 	{
   211 		if (!temp_info[numparams].marked)
   212 		{
   213 			continue;
   214 		}
   215 		if (docopies && temp_info[numparams].flags)
   216 		{
   217 			if (temp_info[numparams].orig_addr)
   218 			{
   219 				if (temp_info[numparams].size == 1)
   220 				{
   221 					*temp_info[numparams].orig_addr = *temp_info[numparams].phys_addr;
   222 				} else {
   223 					memcpy(temp_info[numparams].orig_addr, 
   224 							temp_info[numparams].phys_addr, 
   225 							temp_info[numparams].size * sizeof(cell_t));
   226 				}
   227 			}
   228 		}
   229 		base->HeapPop(temp_info[numparams].local_addr);
   230 		temp_info[numparams].marked = false;
   231 	}
   232 
   233 	return err;
   234 }
   235 
   236 cell_t *CFunction::GetAddressOfPushedParam(unsigned int param)
   237 {
   238 	if (m_errorstate != SP_ERROR_NONE
   239 		|| param >= m_curparam
   240 		|| !m_info[param].marked)
   241 	{
   242 		return NULL;
   243 	}
   244 
   245 	return m_info[param].phys_addr;
   246 }