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