core/vm/sp_vm_function.cpp
author Scott Ehlert <ds@alliedmods.net>
Sun Mar 30 07:00:22 2008 +0000 (2008-03-30)
changeset 1952 b7aa2b626807
permissions -rw-r--r--
Spring Cleaning, Part Ichi (1)
Various minor things done to project files
Updated sample extension project file and updated makefile to the new unified version (more changes likely on the way)
Updated regex project file and makefile
ds@1952
     1
/**
ds@1952
     2
 * vim: set ts=4 :
ds@1952
     3
 * =============================================================================
ds@1952
     4
 * SourcePawn
ds@1952
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
ds@1952
     6
 * =============================================================================
ds@1952
     7
 *
ds@1952
     8
 * This program is free software; you can redistribute it and/or modify it under
ds@1952
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
ds@1952
    10
 * Free Software Foundation.
ds@1952
    11
 * 
ds@1952
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1952
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1952
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
ds@1952
    15
 * details.
ds@1952
    16
 *
ds@1952
    17
 * You should have received a copy of the GNU General Public License along with
ds@1952
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
ds@1952
    19
 *
ds@1952
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
ds@1952
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1952
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1952
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
ds@1952
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
ds@1952
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
ds@1952
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1952
    27
 * or <http://www.sourcemod.net/license.php>.
ds@1952
    28
 *
ds@1952
    29
 * Version: $Id$
ds@1952
    30
 */
ds@1952
    31
ds@1952
    32
#include <stdio.h>
ds@1952
    33
#include <string.h>
ds@1952
    34
#include "sp_vm_function.h"
ds@1952
    35
#include "sm_stringutil.h"
ds@1952
    36
ds@1952
    37
/********************
ds@1952
    38
* FUNCTION CALLING *
ds@1952
    39
********************/
ds@1952
    40
ds@1952
    41
void CFunction::Set(uint32_t code_addr, IPluginContext *plugin, funcid_t id, uint32_t pub_id)
ds@1952
    42
{
ds@1952
    43
	m_codeaddr = code_addr;
ds@1952
    44
	m_pContext = plugin;
ds@1952
    45
	m_curparam = 0;
ds@1952
    46
	m_errorstate = SP_ERROR_NONE;
ds@1952
    47
	m_Invalid = false;
ds@1952
    48
	m_pCtx = plugin ? plugin->GetContext() : NULL;
ds@1952
    49
	m_FnId = id;
ds@1952
    50
	
ds@1952
    51
	m_pContext->GetPublicByIndex(pub_id, &m_pPublic);
ds@1952
    52
}
ds@1952
    53
ds@1952
    54
bool CFunction::IsRunnable()
ds@1952
    55
{
ds@1952
    56
	return ((m_pCtx->flags & SPFLAG_PLUGIN_PAUSED) != SPFLAG_PLUGIN_PAUSED);
ds@1952
    57
}
ds@1952
    58
ds@1952
    59
int CFunction::CallFunction(const cell_t *params, unsigned int num_params, cell_t *result)
ds@1952
    60
{
ds@1952
    61
	int ir, serial;
ds@1952
    62
ds@1952
    63
	if (!IsRunnable())
ds@1952
    64
	{
ds@1952
    65
		return SP_ERROR_NOT_RUNNABLE;
ds@1952
    66
	}
ds@1952
    67
ds@1952
    68
	if ((m_pCtx->prof_flags & SP_PROF_CALLBACKS) == SP_PROF_CALLBACKS
ds@1952
    69
		&& m_pPublic != NULL)
ds@1952
    70
	{
ds@1952
    71
		serial = m_pCtx->profiler->OnCallbackBegin(m_pContext, m_pPublic);
ds@1952
    72
	}
ds@1952
    73
ds@1952
    74
	while (num_params--)
ds@1952
    75
	{
ds@1952
    76
		m_pContext->PushCell(params[num_params]);
ds@1952
    77
	}
ds@1952
    78
ds@1952
    79
	ir = m_pContext->Execute(m_codeaddr, result);
ds@1952
    80
ds@1952
    81
	if ((m_pCtx->prof_flags & SP_PROF_CALLBACKS) == SP_PROF_CALLBACKS
ds@1952
    82
		&& m_pPublic != NULL)
ds@1952
    83
	{
ds@1952
    84
		m_pCtx->profiler->OnCallbackEnd(serial);
ds@1952
    85
	}
ds@1952
    86
ds@1952
    87
	return ir;
ds@1952
    88
}
ds@1952
    89
ds@1952
    90
IPluginContext *CFunction::GetParentContext()
ds@1952
    91
{
ds@1952
    92
	return m_pContext;
ds@1952
    93
}
ds@1952
    94
ds@1952
    95
CFunction::CFunction(uint32_t code_addr, IPluginContext *plugin, funcid_t id, uint32_t pub_id) : 
ds@1952
    96
	m_codeaddr(code_addr), m_pContext(plugin), m_curparam(0), 
ds@1952
    97
	m_errorstate(SP_ERROR_NONE), m_FnId(id)
ds@1952
    98
{
ds@1952
    99
	m_Invalid = false;
ds@1952
   100
	if (plugin)
ds@1952
   101
	{
ds@1952
   102
		m_pCtx = plugin->GetContext();
ds@1952
   103
	}
ds@1952
   104
	m_pContext->GetPublicByIndex(pub_id, &m_pPublic);
ds@1952
   105
}
ds@1952
   106
ds@1952
   107
int CFunction::PushCell(cell_t cell)
ds@1952
   108
{
ds@1952
   109
	if (m_curparam >= SP_MAX_EXEC_PARAMS)
ds@1952
   110
	{
ds@1952
   111
		return SetError(SP_ERROR_PARAMS_MAX);
ds@1952
   112
	}
ds@1952
   113
ds@1952
   114
	m_info[m_curparam].marked = false;
ds@1952
   115
	m_params[m_curparam] = cell;
ds@1952
   116
	m_curparam++;
ds@1952
   117
ds@1952
   118
	return SP_ERROR_NONE;
ds@1952
   119
}
ds@1952
   120
ds@1952
   121
int CFunction::PushCellByRef(cell_t *cell, int flags)
ds@1952
   122
{
ds@1952
   123
	return PushArray(cell, 1, flags);
ds@1952
   124
}
ds@1952
   125
ds@1952
   126
int CFunction::PushFloat(float number)
ds@1952
   127
{
ds@1952
   128
	cell_t val = *(cell_t *)&number;
ds@1952
   129
ds@1952
   130
	return PushCell(val);
ds@1952
   131
}
ds@1952
   132
ds@1952
   133
int CFunction::PushFloatByRef(float *number, int flags)
ds@1952
   134
{
ds@1952
   135
	return PushCellByRef((cell_t *)number, flags);
ds@1952
   136
}
ds@1952
   137
ds@1952
   138
int CFunction::PushArray(cell_t *inarray, unsigned int cells, int copyback)
ds@1952
   139
{
ds@1952
   140
	if (m_curparam >= SP_MAX_EXEC_PARAMS)
ds@1952
   141
	{
ds@1952
   142
		return SetError(SP_ERROR_PARAMS_MAX);
ds@1952
   143
	}
ds@1952
   144
ds@1952
   145
	ParamInfo *info = &m_info[m_curparam];
ds@1952
   146
ds@1952
   147
	info->flags = inarray ? copyback : 0;
ds@1952
   148
	info->marked = true;
ds@1952
   149
	info->size = cells;
ds@1952
   150
	info->str.is_sz = false;
ds@1952
   151
	info->orig_addr = inarray;
ds@1952
   152
ds@1952
   153
	m_curparam++;
ds@1952
   154
ds@1952
   155
	return SP_ERROR_NONE;
ds@1952
   156
}
ds@1952
   157
ds@1952
   158
int CFunction::PushString(const char *string)
ds@1952
   159
{
ds@1952
   160
	return _PushString(string, SM_PARAM_STRING_COPY, 0, strlen(string)+1);
ds@1952
   161
}
ds@1952
   162
ds@1952
   163
int CFunction::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
ds@1952
   164
{
ds@1952
   165
	return _PushString(buffer, sz_flags, cp_flags, length);
ds@1952
   166
}
ds@1952
   167
ds@1952
   168
int CFunction::_PushString(const char *string, int sz_flags, int cp_flags, size_t len)
ds@1952
   169
{
ds@1952
   170
	if (m_curparam >= SP_MAX_EXEC_PARAMS)
ds@1952
   171
	{
ds@1952
   172
		return SetError(SP_ERROR_PARAMS_MAX);
ds@1952
   173
	}
ds@1952
   174
ds@1952
   175
	ParamInfo *info = &m_info[m_curparam];
ds@1952
   176
ds@1952
   177
	info->marked = true;
ds@1952
   178
	info->orig_addr = (cell_t *)string;
ds@1952
   179
	info->flags = cp_flags;
ds@1952
   180
	info->size = len;
ds@1952
   181
	info->str.sz_flags = sz_flags;
ds@1952
   182
	info->str.is_sz = true;
ds@1952
   183
ds@1952
   184
	m_curparam++;
ds@1952
   185
ds@1952
   186
	return SP_ERROR_NONE;
ds@1952
   187
}
ds@1952
   188
ds@1952
   189
void CFunction::Cancel()
ds@1952
   190
{
ds@1952
   191
	if (!m_curparam)
ds@1952
   192
	{
ds@1952
   193
		return;
ds@1952
   194
	}
ds@1952
   195
ds@1952
   196
	m_errorstate = SP_ERROR_NONE;
ds@1952
   197
	m_curparam = 0;
ds@1952
   198
}
ds@1952
   199
ds@1952
   200
int CFunction::Execute(cell_t *result)
ds@1952
   201
{
ds@1952
   202
	int err = SP_ERROR_NONE;
ds@1952
   203
ds@1952
   204
	if (!IsRunnable())
ds@1952
   205
	{
ds@1952
   206
		m_errorstate = SP_ERROR_NOT_RUNNABLE;
ds@1952
   207
	}
ds@1952
   208
ds@1952
   209
	if (m_errorstate != SP_ERROR_NONE)
ds@1952
   210
	{
ds@1952
   211
		err = m_errorstate;
ds@1952
   212
		Cancel();
ds@1952
   213
		return err;
ds@1952
   214
	}
ds@1952
   215
ds@1952
   216
	//This is for re-entrancy!
ds@1952
   217
	cell_t temp_params[SP_MAX_EXEC_PARAMS];
ds@1952
   218
	ParamInfo temp_info[SP_MAX_EXEC_PARAMS];
ds@1952
   219
	unsigned int numparams = m_curparam;
ds@1952
   220
	unsigned int i;
ds@1952
   221
	bool docopies = true;
ds@1952
   222
ds@1952
   223
	if (numparams)
ds@1952
   224
	{
ds@1952
   225
		//Save the info locally, then reset it for re-entrant calls.
ds@1952
   226
		memcpy(temp_info, m_info, numparams * sizeof(ParamInfo));
ds@1952
   227
	}
ds@1952
   228
	m_curparam = 0;
ds@1952
   229
ds@1952
   230
	/* Browse the parameters and build arrays */
ds@1952
   231
	for (i=0; i<numparams; i++)
ds@1952
   232
	{
ds@1952
   233
		/* Is this marked as an array? */
ds@1952
   234
		if (temp_info[i].marked)
ds@1952
   235
		{
ds@1952
   236
			if (!temp_info[i].str.is_sz)
ds@1952
   237
			{
ds@1952
   238
				/* Allocate a normal/generic array */
ds@1952
   239
				if ((err=m_pContext->HeapAlloc(temp_info[i].size, 
ds@1952
   240
											   &(temp_info[i].local_addr),
ds@1952
   241
											   &(temp_info[i].phys_addr)))
ds@1952
   242
					!= SP_ERROR_NONE)
ds@1952
   243
				{
ds@1952
   244
					break;
ds@1952
   245
				}
ds@1952
   246
				if (temp_info[i].orig_addr)
ds@1952
   247
				{
ds@1952
   248
					memcpy(temp_info[i].phys_addr, temp_info[i].orig_addr, sizeof(cell_t) * temp_info[i].size);
ds@1952
   249
				}
ds@1952
   250
			}
ds@1952
   251
			else
ds@1952
   252
			{
ds@1952
   253
				/* Calculate cells required for the string */
ds@1952
   254
				size_t cells = (temp_info[i].size + sizeof(cell_t) - 1) / sizeof(cell_t);
ds@1952
   255
ds@1952
   256
				/* Allocate the buffer */
ds@1952
   257
				if ((err=m_pContext->HeapAlloc(cells,
ds@1952
   258
												&(temp_info[i].local_addr),
ds@1952
   259
												&(temp_info[i].phys_addr)))
ds@1952
   260
					!= SP_ERROR_NONE)
ds@1952
   261
				{
ds@1952
   262
					break;
ds@1952
   263
				}
ds@1952
   264
				/* Copy original string if necessary */
ds@1952
   265
				if ((temp_info[i].str.sz_flags & SM_PARAM_STRING_COPY) && (temp_info[i].orig_addr != NULL))
ds@1952
   266
				{
ds@1952
   267
					/* Cut off UTF-8 properly */
ds@1952
   268
					if (temp_info[i].str.sz_flags & SM_PARAM_STRING_UTF8)
ds@1952
   269
					{
ds@1952
   270
						if ((err=m_pContext->StringToLocalUTF8(temp_info[i].local_addr, 
ds@1952
   271
																temp_info[i].size, 
ds@1952
   272
																(const char *)temp_info[i].orig_addr,
ds@1952
   273
																NULL))
ds@1952
   274
							!= SP_ERROR_NONE)
ds@1952
   275
						{
ds@1952
   276
							break;
ds@1952
   277
						}
ds@1952
   278
					}
ds@1952
   279
					/* Copy a binary blob */
ds@1952
   280
					else if (temp_info[i].str.sz_flags & SM_PARAM_STRING_BINARY)
ds@1952
   281
					{
ds@1952
   282
						memmove(temp_info[i].phys_addr, temp_info[i].orig_addr, temp_info[i].size);
ds@1952
   283
					}
ds@1952
   284
					/* Copy ASCII characters */
ds@1952
   285
					else
ds@1952
   286
					{
ds@1952
   287
						if ((err=m_pContext->StringToLocal(temp_info[i].local_addr,
ds@1952
   288
															temp_info[i].size,
ds@1952
   289
															(const char *)temp_info[i].orig_addr))
ds@1952
   290
							!= SP_ERROR_NONE)
ds@1952
   291
						{
ds@1952
   292
							break;
ds@1952
   293
						}
ds@1952
   294
					}
ds@1952
   295
				}
ds@1952
   296
			} /* End array/string calculation */
ds@1952
   297
			/* Update the pushed parameter with the byref local address */
ds@1952
   298
			temp_params[i] = temp_info[i].local_addr;
ds@1952
   299
		}
ds@1952
   300
		else
ds@1952
   301
		{
ds@1952
   302
			/* Just copy the value normally */
ds@1952
   303
			temp_params[i] = m_params[i];
ds@1952
   304
		}
ds@1952
   305
	}
ds@1952
   306
ds@1952
   307
	/* Make the call if we can */
ds@1952
   308
	if (err == SP_ERROR_NONE)
ds@1952
   309
	{
ds@1952
   310
		if ((err = CallFunction(temp_params, numparams, result)) != SP_ERROR_NONE)
ds@1952
   311
		{
ds@1952
   312
			docopies = false;
ds@1952
   313
		}
ds@1952
   314
	}
ds@1952
   315
	else
ds@1952
   316
	{
ds@1952
   317
		docopies = false;
ds@1952
   318
	}
ds@1952
   319
ds@1952
   320
	/* i should be equal to the last valid parameter + 1 */
ds@1952
   321
	while (i--)
ds@1952
   322
	{
ds@1952
   323
		if (!temp_info[i].marked)
ds@1952
   324
		{
ds@1952
   325
			continue;
ds@1952
   326
		}
ds@1952
   327
ds@1952
   328
		if (docopies && (temp_info[i].flags & SM_PARAM_COPYBACK))
ds@1952
   329
		{
ds@1952
   330
			if (temp_info[i].orig_addr)
ds@1952
   331
			{
ds@1952
   332
				if (temp_info[i].str.is_sz)
ds@1952
   333
				{
ds@1952
   334
					memcpy(temp_info[i].orig_addr, temp_info[i].phys_addr, temp_info[i].size);
ds@1952
   335
				
ds@1952
   336
				}
ds@1952
   337
				else
ds@1952
   338
				{
ds@1952
   339
					if (temp_info[i].size == 1)
ds@1952
   340
					{
ds@1952
   341
						*temp_info[i].orig_addr = *(temp_info[i].phys_addr);
ds@1952
   342
					}
ds@1952
   343
					else
ds@1952
   344
					{
ds@1952
   345
						memcpy(temp_info[i].orig_addr, 
ds@1952
   346
								temp_info[i].phys_addr, 
ds@1952
   347
								temp_info[i].size * sizeof(cell_t));
ds@1952
   348
					}
ds@1952
   349
				}
ds@1952
   350
			}
ds@1952
   351
		}
ds@1952
   352
ds@1952
   353
		if ((err=m_pContext->HeapPop(temp_info[i].local_addr)) != SP_ERROR_NONE)
ds@1952
   354
		{
ds@1952
   355
			return err;
ds@1952
   356
		}
ds@1952
   357
	}
ds@1952
   358
ds@1952
   359
	return err;
ds@1952
   360
}
ds@1952
   361
ds@1952
   362
funcid_t CFunction::GetFunctionID()
ds@1952
   363
{
ds@1952
   364
	return m_FnId;
ds@1952
   365
}
ds@1952
   366