core/systems/CFunction.cpp
author David Anderson <dvander@alliedmods.net>
Wed Jan 17 06:49:59 2007 +0000 (2007-01-17)
changeset 308 f0e65f92cb34
parent 296 993eb3462410
permissions -rw-r--r--
Redesigned how server commands work. The "plugins" command will be back soon.
     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.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.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 * sizeof(cell_t);
    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, SM_PARAM_STRING_COPY, 0, strlen(string)+1);
   116 }
   117 
   118 int CFunction::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
   119 {
   120 	return _PushString(buffer, sz_flags, cp_flags, length);
   121 }
   122 
   123 int CFunction::_PushString(const char *string, int sz_flags, int cp_flags, size_t len)
   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.base;
   131 	ParamInfo *info = &m_info[m_curparam];
   132 	size_t cells = (len + sizeof(cell_t) - 1) / sizeof(cell_t);
   133 	int err;
   134 
   135 	if ((err=base->HeapAlloc(cells, &info->local_addr, &info->phys_addr)) != SP_ERROR_NONE)
   136 	{
   137 		return SetError(err);
   138 	}
   139 
   140 	info->marked = true;
   141 	m_params[m_curparam] = info->local_addr;
   142 	m_curparam++;	/* Prevent a leak */
   143 
   144 	if (!(sz_flags & SM_PARAM_STRING_COPY))
   145 	{
   146 		goto skip_localtostr;
   147 	}
   148 
   149 	if (sz_flags & SM_PARAM_STRING_UTF8)
   150 	{
   151 		if ((err=base->StringToLocalUTF8(info->local_addr, len, string, NULL)) != SP_ERROR_NONE)
   152 		{
   153 			return SetError(err);
   154 		}
   155 	} else {
   156 		if ((err=base->StringToLocal(info->local_addr, len, string)) != SP_ERROR_NONE)
   157 		{
   158 			return SetError(err);
   159 		}
   160 	}
   161 
   162 skip_localtostr:
   163 	info->flags = cp_flags;
   164 	info->orig_addr = (cell_t *)string;
   165 	info->size = len;
   166 
   167 	return SP_ERROR_NONE;
   168 }
   169 
   170 void CFunction::Cancel()
   171 {
   172 	if (!m_curparam)
   173 	{
   174 		return;
   175 	}
   176 
   177 	IPluginContext *base = m_pPlugin->m_ctx.base;
   178 
   179 	while (m_curparam--)
   180 	{
   181 		if (m_info[m_curparam].marked)
   182 		{
   183 			base->HeapRelease(m_info[m_curparam].local_addr);
   184 			m_info[m_curparam].marked = false;
   185 		}
   186 	}
   187 
   188 	m_errorstate = SP_ERROR_NONE;
   189 }
   190 
   191 int CFunction::Execute(cell_t *result)
   192 {
   193 	int err;
   194 	if (m_errorstate != SP_ERROR_NONE)
   195 	{
   196 		err = m_errorstate;
   197 		Cancel();
   198 		return err;
   199 	}
   200 
   201 	//This is for re-entrancy!
   202 	cell_t temp_params[SP_MAX_EXEC_PARAMS];
   203 	ParamInfo temp_info[SP_MAX_EXEC_PARAMS];
   204 	unsigned int numparams = m_curparam;
   205 	bool docopies = true;
   206 
   207 	if (numparams)
   208 	{
   209 		//Save the info locally, then reset it for re-entrant calls.
   210 		memcpy(temp_params, m_params, numparams * sizeof(cell_t));
   211 		memcpy(temp_info, m_info, numparams * sizeof(ParamInfo));
   212 	}
   213 	m_curparam = 0;
   214 
   215 	if ((err = CallFunction(temp_params, numparams, result)) != SP_ERROR_NONE)
   216 	{
   217 		docopies = false;
   218 	}
   219 
   220 	IPluginContext *base = m_pPlugin->m_ctx.base;
   221 
   222 	while (numparams--)
   223 	{
   224 		if (!temp_info[numparams].marked)
   225 		{
   226 			continue;
   227 		}
   228 		if (docopies && temp_info[numparams].flags)
   229 		{
   230 			if (temp_info[numparams].orig_addr)
   231 			{
   232 				if (temp_info[numparams].size == sizeof(cell_t))
   233 				{
   234 					*temp_info[numparams].orig_addr = *temp_info[numparams].phys_addr;
   235 				} else {
   236 					memcpy(temp_info[numparams].orig_addr, 
   237 							temp_info[numparams].phys_addr, 
   238 							temp_info[numparams].size);
   239 				}
   240 			}
   241 		}
   242 		base->HeapPop(temp_info[numparams].local_addr);
   243 		temp_info[numparams].marked = false;
   244 	}
   245 
   246 	return err;
   247 }
   248 
   249 cell_t *CFunction::GetAddressOfPushedParam(unsigned int param)
   250 {
   251 	if (m_errorstate != SP_ERROR_NONE
   252 		|| param >= m_curparam
   253 		|| !m_info[param].marked)
   254 	{
   255 		return NULL;
   256 	}
   257 
   258 	return m_info[param].phys_addr;
   259 }