core/vm/sp_vm_function.cpp
author Scott Ehlert <ds@alliedmods.net>
Mon May 14 21:29:17 2007 +0000 (2007-05-14)
changeset 794 5947b0ee60bb
parent 653 ef60870067ff
child 857 11471aa66e06
permissions -rw-r--r--
Implemented amb286 - .smx extension no longer required with "sm plugins load"
dvander@371
     1
/**
ds@653
     2
 * vim: set ts=4 :
dvander@371
     3
 * ================================================================
dvander@371
     4
 * SourcePawn (C)2004-2007 AlliedModders LLC.  All rights reserved.
dvander@371
     5
 * ================================================================
dvander@371
     6
 *
dvander@371
     7
 * This file is not open source and may not be copied without explicit
dvander@371
     8
 * written permission of AlliedModders LLC.  This file may not be redistributed 
dvander@371
     9
 * in whole or significant part.
dvander@371
    10
 * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
dvander@371
    11
 *
dvander@371
    12
 * Version: $Id$
dvander@371
    13
 */
dvander@371
    14
dvander@327
    15
#include <stdio.h>
dvander@351
    16
#include <string.h>
dvander@327
    17
#include "PluginSys.h"
dvander@327
    18
dvander@327
    19
/********************
dvander@327
    20
* FUNCTION CALLING *
dvander@327
    21
********************/
dvander@327
    22
dvander@348
    23
void CFunction::Set(uint32_t code_addr, IPluginContext *plugin)
dvander@327
    24
{
dvander@348
    25
	m_codeaddr = code_addr;
dvander@327
    26
	m_pContext = plugin;
dvander@327
    27
	m_curparam = 0;
dvander@327
    28
	m_errorstate = SP_ERROR_NONE;
dvander@502
    29
	m_Invalid = false;
dvander@525
    30
	m_pCtx = plugin ? plugin->GetContext() : NULL;
dvander@525
    31
}
dvander@525
    32
dvander@525
    33
bool CFunction::IsRunnable()
dvander@525
    34
{
dvander@525
    35
	return ((m_pCtx->flags & SPFLAG_PLUGIN_PAUSED) != SPFLAG_PLUGIN_PAUSED);
dvander@327
    36
}
dvander@327
    37
dvander@327
    38
int CFunction::CallFunction(const cell_t *params, unsigned int num_params, cell_t *result)
dvander@327
    39
{
dvander@525
    40
	if (!IsRunnable())
dvander@525
    41
	{
dvander@525
    42
		return SP_ERROR_NOT_RUNNABLE;
dvander@525
    43
	}
dvander@525
    44
dvander@327
    45
	while (num_params--)
dvander@327
    46
	{
dvander@327
    47
		m_pContext->PushCell(params[num_params]);
dvander@327
    48
	}
dvander@327
    49
dvander@348
    50
	return m_pContext->Execute(m_codeaddr, result);
dvander@327
    51
}
dvander@327
    52
dvander@327
    53
IPluginContext *CFunction::GetParentContext()
dvander@327
    54
{
dvander@327
    55
	return m_pContext;
dvander@327
    56
}
dvander@327
    57
dvander@348
    58
CFunction::CFunction(uint32_t code_addr, IPluginContext *plugin) : 
dvander@348
    59
	m_codeaddr(code_addr), m_pContext(plugin), m_curparam(0), 
dvander@327
    60
	m_errorstate(SP_ERROR_NONE)
dvander@327
    61
{
dvander@502
    62
	m_Invalid = false;
dvander@525
    63
	if (plugin)
dvander@525
    64
	{
dvander@525
    65
		m_pCtx = plugin->GetContext();
dvander@525
    66
	}
dvander@327
    67
}
dvander@327
    68
dvander@327
    69
int CFunction::PushCell(cell_t cell)
dvander@327
    70
{
dvander@327
    71
	if (m_curparam >= SP_MAX_EXEC_PARAMS)
dvander@327
    72
	{
dvander@327
    73
		return SetError(SP_ERROR_PARAMS_MAX);
dvander@327
    74
	}
dvander@327
    75
dvander@327
    76
	m_info[m_curparam].marked = false;
dvander@327
    77
	m_params[m_curparam] = cell;
dvander@327
    78
	m_curparam++;
dvander@327
    79
dvander@327
    80
	return SP_ERROR_NONE;
dvander@327
    81
}
dvander@327
    82
ds@585
    83
int CFunction::PushCellByRef(cell_t *cell, int flags)
dvander@327
    84
{
dvander@589
    85
	return PushArray(cell, 1, flags);
dvander@327
    86
}
dvander@327
    87
dvander@327
    88
int CFunction::PushFloat(float number)
dvander@327
    89
{
dvander@327
    90
	cell_t val = *(cell_t *)&number;
dvander@327
    91
dvander@327
    92
	return PushCell(val);
dvander@327
    93
}
dvander@327
    94
ds@585
    95
int CFunction::PushFloatByRef(float *number, int flags)
dvander@327
    96
{
ds@585
    97
	return PushCellByRef((cell_t *)number, flags);
dvander@327
    98
}
dvander@327
    99
dvander@589
   100
int CFunction::PushArray(cell_t *inarray, unsigned int cells, int copyback)
dvander@327
   101
{
dvander@327
   102
	if (m_curparam >= SP_MAX_EXEC_PARAMS)
dvander@327
   103
	{
dvander@327
   104
		return SetError(SP_ERROR_PARAMS_MAX);
dvander@327
   105
	}
dvander@327
   106
dvander@327
   107
	ParamInfo *info = &m_info[m_curparam];
dvander@327
   108
dvander@327
   109
	info->flags = inarray ? copyback : 0;
dvander@327
   110
	info->marked = true;
dvander@589
   111
	info->size = cells;
dvander@589
   112
	info->str.is_sz = false;
dvander@589
   113
	info->orig_addr = inarray;
dvander@327
   114
dvander@589
   115
	m_curparam++;
dvander@327
   116
dvander@586
   117
	return SP_ERROR_NONE;
dvander@327
   118
}
dvander@327
   119
dvander@327
   120
int CFunction::PushString(const char *string)
dvander@327
   121
{
dvander@327
   122
	return _PushString(string, SM_PARAM_STRING_COPY, 0, strlen(string)+1);
dvander@327
   123
}
dvander@327
   124
dvander@327
   125
int CFunction::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
dvander@327
   126
{
dvander@327
   127
	return _PushString(buffer, sz_flags, cp_flags, length);
dvander@327
   128
}
dvander@327
   129
dvander@327
   130
int CFunction::_PushString(const char *string, int sz_flags, int cp_flags, size_t len)
dvander@327
   131
{
dvander@327
   132
	if (m_curparam >= SP_MAX_EXEC_PARAMS)
dvander@327
   133
	{
dvander@327
   134
		return SetError(SP_ERROR_PARAMS_MAX);
dvander@327
   135
	}
dvander@327
   136
dvander@327
   137
	ParamInfo *info = &m_info[m_curparam];
dvander@327
   138
dvander@327
   139
	info->marked = true;
dvander@589
   140
	info->orig_addr = (cell_t *)string;
dvander@589
   141
	info->flags = cp_flags;
dvander@589
   142
	info->size = len;
dvander@589
   143
	info->str.sz_flags = sz_flags;
dvander@589
   144
	info->str.is_sz = true;
dvander@327
   145
dvander@589
   146
	m_curparam++;
dvander@327
   147
dvander@327
   148
	return SP_ERROR_NONE;
dvander@327
   149
}
dvander@327
   150
dvander@327
   151
void CFunction::Cancel()
dvander@327
   152
{
dvander@327
   153
	if (!m_curparam)
dvander@327
   154
	{
dvander@327
   155
		return;
dvander@327
   156
	}
dvander@327
   157
dvander@327
   158
	m_errorstate = SP_ERROR_NONE;
dvander@589
   159
	m_curparam = 0;
dvander@327
   160
}
dvander@327
   161
dvander@327
   162
int CFunction::Execute(cell_t *result)
dvander@327
   163
{
dvander@589
   164
	int err = SP_ERROR_NONE;
dvander@525
   165
	if (!IsRunnable())
dvander@525
   166
	{
dvander@525
   167
		m_errorstate = SP_ERROR_NOT_RUNNABLE;
dvander@525
   168
	}
dvander@327
   169
	if (m_errorstate != SP_ERROR_NONE)
dvander@327
   170
	{
dvander@327
   171
		err = m_errorstate;
dvander@327
   172
		Cancel();
dvander@327
   173
		return err;
dvander@327
   174
	}
dvander@327
   175
dvander@327
   176
	//This is for re-entrancy!
dvander@327
   177
	cell_t temp_params[SP_MAX_EXEC_PARAMS];
dvander@327
   178
	ParamInfo temp_info[SP_MAX_EXEC_PARAMS];
dvander@327
   179
	unsigned int numparams = m_curparam;
dvander@589
   180
	unsigned int i;
dvander@327
   181
	bool docopies = true;
dvander@327
   182
dvander@327
   183
	if (numparams)
dvander@327
   184
	{
dvander@327
   185
		//Save the info locally, then reset it for re-entrant calls.
dvander@327
   186
		memcpy(temp_info, m_info, numparams * sizeof(ParamInfo));
dvander@327
   187
	}
dvander@327
   188
	m_curparam = 0;
dvander@327
   189
dvander@589
   190
	/* Browse the parameters and build arrays */
dvander@589
   191
	for (i=0; i<numparams; i++)
dvander@327
   192
	{
dvander@589
   193
		/* Is this marked as an array? */
dvander@589
   194
		if (temp_info[i].marked)
dvander@589
   195
		{
dvander@589
   196
			if (!temp_info[i].str.is_sz)
dvander@589
   197
			{
dvander@589
   198
				/* Allocate a normal/generic array */
dvander@589
   199
				if ((err=m_pContext->HeapAlloc(temp_info[i].size, 
dvander@589
   200
											   &(temp_info[i].local_addr),
dvander@589
   201
											   &(temp_info[i].phys_addr)))
dvander@589
   202
					!= SP_ERROR_NONE)
dvander@589
   203
				{
dvander@589
   204
					break;
dvander@589
   205
				}
dvander@589
   206
				if (temp_info[i].orig_addr)
dvander@589
   207
				{
dvander@589
   208
					memcpy(temp_info[i].phys_addr, temp_info[i].orig_addr, sizeof(cell_t) * temp_info[i].size);
dvander@589
   209
				}
dvander@589
   210
			} else {
dvander@589
   211
				/* Calculate cells required for the string */
dvander@589
   212
				size_t cells = (temp_info[i].size + sizeof(cell_t) - 1) / sizeof(cell_t);
dvander@589
   213
dvander@589
   214
				/* Allocate the buffer */
dvander@589
   215
				if ((err=m_pContext->HeapAlloc(cells,
dvander@589
   216
												&(temp_info[i].local_addr),
dvander@589
   217
												&(temp_info[i].phys_addr)))
dvander@589
   218
					!= SP_ERROR_NONE)
dvander@589
   219
				{
dvander@589
   220
					break;
dvander@589
   221
				}
dvander@589
   222
				/* Copy original string if necessary */
dvander@589
   223
				if ((temp_info[i].str.sz_flags & SM_PARAM_STRING_COPY) && (temp_info[i].orig_addr != NULL))
dvander@589
   224
				{
dvander@589
   225
					if (temp_info[i].str.sz_flags & SM_PARAM_STRING_UTF8)
dvander@589
   226
					{
dvander@589
   227
						if ((err=m_pContext->StringToLocalUTF8(temp_info[i].local_addr, 
dvander@589
   228
																temp_info[i].size, 
dvander@589
   229
																(const char *)temp_info[i].orig_addr,
dvander@589
   230
																NULL))
dvander@589
   231
							!= SP_ERROR_NONE)
dvander@589
   232
						{
dvander@589
   233
							break;
dvander@589
   234
						}
dvander@589
   235
					} else {
dvander@589
   236
						if ((err=m_pContext->StringToLocal(temp_info[i].local_addr,
dvander@589
   237
															temp_info[i].size,
dvander@589
   238
															(const char *)temp_info[i].orig_addr))
dvander@589
   239
							!= SP_ERROR_NONE)
dvander@589
   240
						{
dvander@589
   241
							break;
dvander@589
   242
						}
dvander@589
   243
					}
dvander@589
   244
				}
dvander@589
   245
			} /* End array/string calculation */
dvander@589
   246
			/* Update the pushed parameter with the byref local address */
dvander@589
   247
			temp_params[i] = temp_info[i].local_addr;
dvander@589
   248
		} else {
dvander@589
   249
			/* Just copy the value normally */
dvander@589
   250
			temp_params[i] = m_params[i];
dvander@589
   251
		}
dvander@589
   252
	}
dvander@589
   253
dvander@589
   254
	/* Make the call if we can */
dvander@589
   255
	if (err == SP_ERROR_NONE)
dvander@589
   256
	{
dvander@589
   257
		if ((err = CallFunction(temp_params, numparams, result)) != SP_ERROR_NONE)
dvander@589
   258
		{
dvander@589
   259
			docopies = false;
dvander@589
   260
		}
dvander@589
   261
	} else {
dvander@327
   262
		docopies = false;
dvander@327
   263
	}
dvander@327
   264
dvander@589
   265
	/* i should be equal to the last valid parameter + 1 */
dvander@589
   266
	while (i--)
dvander@327
   267
	{
dvander@589
   268
		if (!temp_info[i].marked)
dvander@327
   269
		{
dvander@327
   270
			continue;
dvander@327
   271
		}
dvander@589
   272
		if (docopies && (temp_info[i].flags & SM_PARAM_COPYBACK))
dvander@327
   273
		{
dvander@589
   274
			if (temp_info[i].orig_addr)
dvander@327
   275
			{
dvander@589
   276
				if (temp_info[i].str.is_sz)
dvander@327
   277
				{
dvander@589
   278
					memcpy(temp_info[i].orig_addr, temp_info[i].phys_addr, temp_info[i].size);
dvander@327
   279
				} else {
dvander@589
   280
					if (temp_info[i].size == 1)
dvander@589
   281
					{
dvander@589
   282
						*temp_info[i].orig_addr = *(temp_info[i].phys_addr);
dvander@589
   283
					} else {
dvander@589
   284
						memcpy(temp_info[i].orig_addr, 
dvander@589
   285
								temp_info[i].phys_addr, 
dvander@589
   286
								temp_info[i].size * sizeof(cell_t));
dvander@589
   287
					}
dvander@327
   288
				}
dvander@327
   289
			}
dvander@327
   290
		}
dvander@589
   291
		if ((err=m_pContext->HeapPop(temp_info[i].local_addr)) != SP_ERROR_NONE)
dvander@589
   292
		{
dvander@589
   293
			return err;
dvander@589
   294
		}
dvander@327
   295
	}
dvander@327
   296
dvander@327
   297
	return err;
dvander@327
   298
}