core/systems/ForwardSys.cpp
author David Anderson <dvander@alliedmods.net>
Sun Jul 06 04:49:55 2008 +0000 (2008-07-06)
branchrefac-jit
changeset 2168 c24a6fa957db
permissions -rw-r--r--
jit refactoring branch
dvander@2168
     1
/**
dvander@2168
     2
 * vim: set ts=4 :
dvander@2168
     3
 * =============================================================================
dvander@2168
     4
 * SourceMod
dvander@2168
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
dvander@2168
     6
 * =============================================================================
dvander@2168
     7
 *
dvander@2168
     8
 * This program is free software; you can redistribute it and/or modify it under
dvander@2168
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
dvander@2168
    10
 * Free Software Foundation.
dvander@2168
    11
 * 
dvander@2168
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
dvander@2168
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
dvander@2168
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
dvander@2168
    15
 * details.
dvander@2168
    16
 *
dvander@2168
    17
 * You should have received a copy of the GNU General Public License along with
dvander@2168
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
dvander@2168
    19
 *
dvander@2168
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
dvander@2168
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
dvander@2168
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
dvander@2168
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
dvander@2168
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
dvander@2168
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
dvander@2168
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
dvander@2168
    27
 * or <http://www.sourcemod.net/license.php>.
dvander@2168
    28
 *
dvander@2168
    29
 * Version: $Id$
dvander@2168
    30
 */
dvander@2168
    31
dvander@2168
    32
#include <assert.h>
dvander@2168
    33
#include <stdarg.h>
dvander@2168
    34
#include <string.h>
dvander@2168
    35
#include "ForwardSys.h"
dvander@2168
    36
#include "PluginSys.h"
dvander@2168
    37
#include "ShareSys.h"
dvander@2168
    38
#include "DebugReporter.h"
dvander@2168
    39
dvander@2168
    40
CForwardManager g_Forwards;
dvander@2168
    41
dvander@2168
    42
/**
dvander@2168
    43
 * Genesis turns to its source, reduction occurs stepwise although the essence is all one.
dvander@2168
    44
 * End of line.  FTL system check.
dvander@2168
    45
 *
dvander@2168
    46
 * :TODO: WHAT NEEDS TO BE TESTED IN THIS BEAST
dvander@2168
    47
 * VARARG FUNCTIONS:
dvander@2168
    48
 * - Pushing no varargs
dvander@2168
    49
 */
dvander@2168
    50
dvander@2168
    51
// :TODO: IMPORTANT!!! The result pointer arg in the execute function maybe invalid if the forward fails
dvander@2168
    52
// so later evaluation of this result may cause problems on higher levels of abstraction. DOCUMENT OR FIX ALL FORWARDS!
dvander@2168
    53
dvander@2168
    54
CForwardManager::~CForwardManager()
dvander@2168
    55
{
dvander@2168
    56
	CStack<CForward *>::iterator iter;
dvander@2168
    57
	for (iter=m_FreeForwards.begin(); iter!=m_FreeForwards.end(); iter++)
dvander@2168
    58
	{
dvander@2168
    59
		delete (*iter);
dvander@2168
    60
	}
dvander@2168
    61
	m_FreeForwards.popall();
dvander@2168
    62
}
dvander@2168
    63
dvander@2168
    64
void CForwardManager::OnSourceModAllInitialized()
dvander@2168
    65
{
dvander@2168
    66
	g_PluginSys.AddPluginsListener(this);
dvander@2168
    67
	g_ShareSys.AddInterface(NULL, this);
dvander@2168
    68
}
dvander@2168
    69
dvander@2168
    70
IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned int num_params, const ParamType *types, ...)
dvander@2168
    71
{
dvander@2168
    72
	CForward *fwd;
dvander@2168
    73
	va_list ap;
dvander@2168
    74
	va_start(ap, types);
dvander@2168
    75
	
dvander@2168
    76
	fwd = CForward::CreateForward(name, et, num_params, types, ap);
dvander@2168
    77
dvander@2168
    78
	va_end(ap);
dvander@2168
    79
dvander@2168
    80
	if (fwd)
dvander@2168
    81
	{
dvander@2168
    82
		g_PluginSys.AddFunctionsToForward(name, fwd);
dvander@2168
    83
dvander@2168
    84
		m_managed.push_back(fwd);
dvander@2168
    85
	}
dvander@2168
    86
dvander@2168
    87
	return fwd;
dvander@2168
    88
}
dvander@2168
    89
dvander@2168
    90
IChangeableForward *CForwardManager::CreateForwardEx(const char *name, ExecType et, int num_params, const ParamType *types, ...)
dvander@2168
    91
{
dvander@2168
    92
	CForward *fwd;
dvander@2168
    93
	va_list ap;
dvander@2168
    94
	va_start(ap, types);
dvander@2168
    95
dvander@2168
    96
	fwd = CForward::CreateForward(name, et, num_params, types, ap);
dvander@2168
    97
dvander@2168
    98
	va_end(ap);
dvander@2168
    99
dvander@2168
   100
	if (fwd)
dvander@2168
   101
	{
dvander@2168
   102
		m_unmanaged.push_back(fwd);
dvander@2168
   103
	}
dvander@2168
   104
dvander@2168
   105
	return fwd;
dvander@2168
   106
}
dvander@2168
   107
dvander@2168
   108
void CForwardManager::OnPluginLoaded(IPlugin *plugin)
dvander@2168
   109
{
dvander@2168
   110
	/* Attach any globally managed forwards */
dvander@2168
   111
	List<CForward *>::iterator iter;
dvander@2168
   112
	CForward *fwd;
dvander@2168
   113
dvander@2168
   114
	for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
dvander@2168
   115
	{
dvander@2168
   116
		fwd = (*iter);
dvander@2168
   117
		IPluginFunction *pFunc = plugin->GetBaseContext()->GetFunctionByName(fwd->GetForwardName());
dvander@2168
   118
		if (pFunc)
dvander@2168
   119
		{
dvander@2168
   120
			fwd->AddFunction(pFunc);
dvander@2168
   121
		}
dvander@2168
   122
	}
dvander@2168
   123
}
dvander@2168
   124
dvander@2168
   125
void CForwardManager::OnPluginUnloaded(IPlugin *plugin)
dvander@2168
   126
{
dvander@2168
   127
	List<CForward *>::iterator iter;
dvander@2168
   128
	CForward *fwd;
dvander@2168
   129
dvander@2168
   130
	for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
dvander@2168
   131
	{
dvander@2168
   132
		fwd = (*iter);
dvander@2168
   133
		fwd->RemoveFunctionsOfPlugin(plugin);
dvander@2168
   134
	}
dvander@2168
   135
dvander@2168
   136
	for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
dvander@2168
   137
	{
dvander@2168
   138
		fwd = (*iter);
dvander@2168
   139
		fwd->RemoveFunctionsOfPlugin(plugin);
dvander@2168
   140
	}
dvander@2168
   141
}
dvander@2168
   142
dvander@2168
   143
IForward *CForwardManager::FindForward(const char *name, IChangeableForward **ifchng)
dvander@2168
   144
{
dvander@2168
   145
	List<CForward *>::iterator iter;
dvander@2168
   146
	CForward *fwd;
dvander@2168
   147
dvander@2168
   148
	for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
dvander@2168
   149
	{
dvander@2168
   150
		fwd = (*iter);
dvander@2168
   151
		if (strcmp(fwd->GetForwardName(), name) == 0)
dvander@2168
   152
		{
dvander@2168
   153
			if (ifchng)
dvander@2168
   154
			{
dvander@2168
   155
				*ifchng = NULL;
dvander@2168
   156
			}
dvander@2168
   157
			return fwd;
dvander@2168
   158
		}
dvander@2168
   159
	}
dvander@2168
   160
dvander@2168
   161
	for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
dvander@2168
   162
	{
dvander@2168
   163
		fwd = (*iter);
dvander@2168
   164
		if (strcmp(fwd->GetForwardName(), name) == 0)
dvander@2168
   165
		{
dvander@2168
   166
			if (ifchng)
dvander@2168
   167
			{
dvander@2168
   168
				*ifchng = fwd;
dvander@2168
   169
			}
dvander@2168
   170
			return fwd;
dvander@2168
   171
		}
dvander@2168
   172
	}
dvander@2168
   173
dvander@2168
   174
	if (ifchng)
dvander@2168
   175
	{
dvander@2168
   176
		*ifchng = NULL;
dvander@2168
   177
	}
dvander@2168
   178
dvander@2168
   179
	return NULL;
dvander@2168
   180
}
dvander@2168
   181
dvander@2168
   182
void CForwardManager::ReleaseForward(IForward *forward)
dvander@2168
   183
{
dvander@2168
   184
	ForwardFree(static_cast<CForward *>(forward));
dvander@2168
   185
}
dvander@2168
   186
dvander@2168
   187
void CForwardManager::ForwardFree(CForward *fwd)
dvander@2168
   188
{
dvander@2168
   189
	if (fwd == NULL)
dvander@2168
   190
	{
dvander@2168
   191
		return;
dvander@2168
   192
	}
dvander@2168
   193
dvander@2168
   194
	m_FreeForwards.push(fwd);
dvander@2168
   195
	m_managed.remove(fwd);
dvander@2168
   196
}
dvander@2168
   197
dvander@2168
   198
CForward *CForwardManager::ForwardMake()
dvander@2168
   199
{
dvander@2168
   200
	CForward *fwd;
dvander@2168
   201
	if (m_FreeForwards.empty())
dvander@2168
   202
	{
dvander@2168
   203
		fwd = new CForward;
dvander@2168
   204
	} else {
dvander@2168
   205
		fwd = m_FreeForwards.front();
dvander@2168
   206
		m_FreeForwards.pop();
dvander@2168
   207
	}
dvander@2168
   208
	return fwd;
dvander@2168
   209
}
dvander@2168
   210
dvander@2168
   211
void CForwardManager::OnPluginPauseChange(IPlugin *plugin, bool paused)
dvander@2168
   212
{
dvander@2168
   213
	/* No longer used */
dvander@2168
   214
}
dvander@2168
   215
dvander@2168
   216
/*************************************
dvander@2168
   217
 * ACTUAL FORWARD API IMPLEMENTATION *
dvander@2168
   218
 *************************************/
dvander@2168
   219
dvander@2168
   220
CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int num_params, const ParamType *types, va_list ap)
dvander@2168
   221
{
dvander@2168
   222
	ParamType _types[SP_MAX_EXEC_PARAMS];
dvander@2168
   223
dvander@2168
   224
	if (num_params > SP_MAX_EXEC_PARAMS)
dvander@2168
   225
	{
dvander@2168
   226
		return NULL;
dvander@2168
   227
	}
dvander@2168
   228
	
dvander@2168
   229
	if (types == NULL && num_params)
dvander@2168
   230
	{
dvander@2168
   231
		for (unsigned int i=0; i<num_params; i++)
dvander@2168
   232
		{
dvander@2168
   233
			_types[i] = (ParamType)va_arg(ap, int);
dvander@2168
   234
			if (_types[i] == Param_VarArgs && (i != num_params - 1))
dvander@2168
   235
			{
dvander@2168
   236
				return NULL;
dvander@2168
   237
			}
dvander@2168
   238
		}
dvander@2168
   239
		types = _types;
dvander@2168
   240
	} else {
dvander@2168
   241
		for (unsigned int i=0; i<num_params; i++)
dvander@2168
   242
		{
dvander@2168
   243
			_types[i] = types[i];
dvander@2168
   244
			if (types[i] == Param_VarArgs && (i != num_params - 1))
dvander@2168
   245
			{
dvander@2168
   246
				return NULL;
dvander@2168
   247
			}
dvander@2168
   248
		}
dvander@2168
   249
	}
dvander@2168
   250
dvander@2168
   251
	/* First parameter can never be varargs */
dvander@2168
   252
	if (num_params && _types[0] == Param_VarArgs)
dvander@2168
   253
	{
dvander@2168
   254
		return NULL;
dvander@2168
   255
	}
dvander@2168
   256
dvander@2168
   257
	CForward *pForward = g_Forwards.ForwardMake();
dvander@2168
   258
	pForward->m_curparam = 0;
dvander@2168
   259
	pForward->m_ExecType = et;
dvander@2168
   260
	snprintf(pForward->m_name, FORWARDS_NAME_MAX, "%s", name ? name : "");
dvander@2168
   261
	
dvander@2168
   262
	for (unsigned int i=0; i<num_params; i++)
dvander@2168
   263
	{
dvander@2168
   264
		pForward->m_types[i] = _types[i];
dvander@2168
   265
	}
dvander@2168
   266
dvander@2168
   267
	if (num_params && _types[num_params-1] == Param_VarArgs)
dvander@2168
   268
	{
dvander@2168
   269
		pForward->m_varargs = num_params--;
dvander@2168
   270
	} else {
dvander@2168
   271
		pForward->m_varargs = false;
dvander@2168
   272
	}
dvander@2168
   273
dvander@2168
   274
	pForward->m_numparams = num_params;
dvander@2168
   275
	pForward->m_errstate = SP_ERROR_NONE;
dvander@2168
   276
dvander@2168
   277
	pForward->m_functions.clear();
dvander@2168
   278
dvander@2168
   279
	return pForward;
dvander@2168
   280
}
dvander@2168
   281
dvander@2168
   282
int CForward::Execute(cell_t *result, IForwardFilter *filter)
dvander@2168
   283
{
dvander@2168
   284
	if (m_errstate)
dvander@2168
   285
	{
dvander@2168
   286
		int err = m_errstate;
dvander@2168
   287
		Cancel();
dvander@2168
   288
		return err;
dvander@2168
   289
	}
dvander@2168
   290
dvander@2168
   291
	if (filter)
dvander@2168
   292
	{
dvander@2168
   293
		filter->OnExecuteBegin();
dvander@2168
   294
	}
dvander@2168
   295
dvander@2168
   296
	FuncIter iter = m_functions.begin();
dvander@2168
   297
	IPluginFunction *func;
dvander@2168
   298
	cell_t cur_result = 0;
dvander@2168
   299
	cell_t high_result = 0;
dvander@2168
   300
	int err;
dvander@2168
   301
	unsigned int failed=0, success=0;
dvander@2168
   302
	unsigned int num_params = m_curparam;
dvander@2168
   303
	FwdParamInfo temp_info[SP_MAX_EXEC_PARAMS];
dvander@2168
   304
	FwdParamInfo *param;
dvander@2168
   305
	ParamType type;
dvander@2168
   306
dvander@2168
   307
	/* Save local, reset */
dvander@2168
   308
	memcpy(temp_info, m_params, sizeof(m_params));
dvander@2168
   309
	m_curparam = 0;
dvander@2168
   310
dvander@2168
   311
	for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
dvander@2168
   312
	{
dvander@2168
   313
		func = (*iter);
dvander@2168
   314
dvander@2168
   315
		for (unsigned int i=0; i<num_params; i++)
dvander@2168
   316
		{
dvander@2168
   317
			int err = SP_ERROR_PARAM;
dvander@2168
   318
			param = &temp_info[i];
dvander@2168
   319
			if (i >= m_numparams || m_types[i] == Param_Any)
dvander@2168
   320
			{
dvander@2168
   321
				type = param->pushedas;
dvander@2168
   322
			} else {
dvander@2168
   323
				type = m_types[i];
dvander@2168
   324
			}
dvander@2168
   325
			if ((i >= m_numparams) || (type & SP_PARAMFLAG_BYREF))
dvander@2168
   326
			{
dvander@2168
   327
				/* If we're byref or we're vararg, we always push everything by ref.
dvander@2168
   328
				 * Even if they're byval, we must push them byref.
dvander@2168
   329
				 */
dvander@2168
   330
				if (type == Param_String)
dvander@2168
   331
				{
dvander@2168
   332
					err = func->PushStringEx((char *)param->byref.orig_addr, param->byref.cells, param->byref.sz_flags, param->byref.flags);
dvander@2168
   333
				} else if (type == Param_Float || type == Param_Cell) {
dvander@2168
   334
					err = func->PushCellByRef(&param->val); 
dvander@2168
   335
				} else {
dvander@2168
   336
					err = func->PushArray(param->byref.orig_addr, param->byref.cells, param->byref.flags);
dvander@2168
   337
					assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef);
dvander@2168
   338
				}
dvander@2168
   339
			} else {
dvander@2168
   340
				/* If we're not byref or not vararg, our job is a bit easier. */
dvander@2168
   341
				assert(type == Param_Cell || type == Param_Float);
dvander@2168
   342
				err = func->PushCell(param->val);
dvander@2168
   343
			}
dvander@2168
   344
			if (err != SP_ERROR_NONE)
dvander@2168
   345
			{
dvander@2168
   346
				if (!filter || !filter->OnErrorReport(this, func, err))
dvander@2168
   347
				{
dvander@2168
   348
					g_DbgReporter.GenerateError(func->GetParentContext(), 
dvander@2168
   349
						func->GetFunctionID(), 
dvander@2168
   350
						err, 
dvander@2168
   351
						"Failed to push parameter while executing forward");
dvander@2168
   352
				}
dvander@2168
   353
				continue;
dvander@2168
   354
			}
dvander@2168
   355
		}
dvander@2168
   356
		
dvander@2168
   357
		/* Call the function and deal with the return value. */
dvander@2168
   358
		if ((err=func->Execute(&cur_result)) != SP_ERROR_NONE)
dvander@2168
   359
		{
dvander@2168
   360
			if (filter)
dvander@2168
   361
			{
dvander@2168
   362
				filter->OnErrorReport(this, func, err);
dvander@2168
   363
			}
dvander@2168
   364
			failed++;
dvander@2168
   365
		} else {
dvander@2168
   366
			success++;
dvander@2168
   367
			switch (m_ExecType)
dvander@2168
   368
			{
dvander@2168
   369
			case ET_Event:
dvander@2168
   370
				{
dvander@2168
   371
					if (cur_result > high_result)
dvander@2168
   372
					{
dvander@2168
   373
						high_result = cur_result;
dvander@2168
   374
					}
dvander@2168
   375
					break;
dvander@2168
   376
				}
dvander@2168
   377
			case ET_Hook:
dvander@2168
   378
				{
dvander@2168
   379
					if (cur_result > high_result)
dvander@2168
   380
					{
dvander@2168
   381
						high_result = cur_result;
dvander@2168
   382
						if ((ResultType)high_result == Pl_Stop)
dvander@2168
   383
						{
dvander@2168
   384
							goto done;
dvander@2168
   385
						}
dvander@2168
   386
					}
dvander@2168
   387
					break;
dvander@2168
   388
				}
dvander@2168
   389
			case ET_Custom:
dvander@2168
   390
				{
dvander@2168
   391
					if (filter)
dvander@2168
   392
					{
dvander@2168
   393
						if (filter->OnFunctionReturn(this, func, &cur_result) == Pl_Stop)
dvander@2168
   394
						{
dvander@2168
   395
							goto done;
dvander@2168
   396
						}
dvander@2168
   397
					}
dvander@2168
   398
					break;
dvander@2168
   399
				}
dvander@2168
   400
			default:
dvander@2168
   401
				{
dvander@2168
   402
					break;
dvander@2168
   403
				}
dvander@2168
   404
			}
dvander@2168
   405
		}
dvander@2168
   406
	}
dvander@2168
   407
dvander@2168
   408
done:
dvander@2168
   409
	if (success)
dvander@2168
   410
	{
dvander@2168
   411
		if (m_ExecType == ET_Event || m_ExecType == ET_Hook)
dvander@2168
   412
		{
dvander@2168
   413
			cur_result = high_result;
dvander@2168
   414
		} else if (m_ExecType == ET_Ignore) {
dvander@2168
   415
			cur_result = 0;
dvander@2168
   416
		}
dvander@2168
   417
		if (result)
dvander@2168
   418
		{
dvander@2168
   419
			*result = cur_result;
dvander@2168
   420
		}
dvander@2168
   421
	}
dvander@2168
   422
dvander@2168
   423
	if (filter)
dvander@2168
   424
	{
dvander@2168
   425
		filter->OnExecuteEnd(&cur_result, success, failed);
dvander@2168
   426
	}
dvander@2168
   427
dvander@2168
   428
	return SP_ERROR_NONE;
dvander@2168
   429
}
dvander@2168
   430
dvander@2168
   431
int CForward::PushCell(cell_t cell)
dvander@2168
   432
{
dvander@2168
   433
	if (m_curparam < m_numparams)
dvander@2168
   434
	{
dvander@2168
   435
		if (m_types[m_curparam] == Param_Any)
dvander@2168
   436
		{
dvander@2168
   437
			m_params[m_curparam].pushedas = Param_Cell;
dvander@2168
   438
		} else if (m_types[m_curparam] != Param_Cell) {
dvander@2168
   439
			return SetError(SP_ERROR_PARAM);
dvander@2168
   440
		}
dvander@2168
   441
	} else {
dvander@2168
   442
		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
dvander@2168
   443
		{
dvander@2168
   444
			return SetError(SP_ERROR_PARAMS_MAX);
dvander@2168
   445
		}
dvander@2168
   446
		m_params[m_curparam].pushedas = Param_Cell;
dvander@2168
   447
	}
dvander@2168
   448
dvander@2168
   449
	m_params[m_curparam++].val = cell;
dvander@2168
   450
dvander@2168
   451
	return SP_ERROR_NONE;
dvander@2168
   452
}
dvander@2168
   453
dvander@2168
   454
int CForward::PushFloat(float number)
dvander@2168
   455
{
dvander@2168
   456
	if (m_curparam < m_numparams)
dvander@2168
   457
	{
dvander@2168
   458
		if (m_types[m_curparam] == Param_Any)
dvander@2168
   459
		{
dvander@2168
   460
			m_params[m_curparam].pushedas = Param_Float;
dvander@2168
   461
		} else if (m_types[m_curparam] != Param_Float) {
dvander@2168
   462
			return SetError(SP_ERROR_PARAM);
dvander@2168
   463
		}
dvander@2168
   464
	} else {
dvander@2168
   465
		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
dvander@2168
   466
		{
dvander@2168
   467
			return SetError(SP_ERROR_PARAMS_MAX);
dvander@2168
   468
		}
dvander@2168
   469
		m_params[m_curparam].pushedas = Param_Float;
dvander@2168
   470
	}
dvander@2168
   471
dvander@2168
   472
	m_params[m_curparam++].val = *(cell_t *)&number;
dvander@2168
   473
dvander@2168
   474
	return SP_ERROR_NONE;
dvander@2168
   475
}
dvander@2168
   476
dvander@2168
   477
int CForward::PushCellByRef(cell_t *cell, int flags)
dvander@2168
   478
{
dvander@2168
   479
	if (m_curparam < m_numparams)
dvander@2168
   480
	{
dvander@2168
   481
		if (m_types[m_curparam] == Param_Any)
dvander@2168
   482
		{
dvander@2168
   483
			m_params[m_curparam].pushedas = Param_CellByRef;
dvander@2168
   484
		} else if (m_types[m_curparam] != Param_CellByRef) {
dvander@2168
   485
			return SetError(SP_ERROR_PARAM);
dvander@2168
   486
		}
dvander@2168
   487
	} else {
dvander@2168
   488
		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
dvander@2168
   489
		{
dvander@2168
   490
			return SetError(SP_ERROR_PARAMS_MAX);
dvander@2168
   491
		}
dvander@2168
   492
		m_params[m_curparam].pushedas = Param_CellByRef;
dvander@2168
   493
	}
dvander@2168
   494
dvander@2168
   495
	_Int_PushArray(cell, 1, flags);
dvander@2168
   496
	m_curparam++;
dvander@2168
   497
dvander@2168
   498
	return SP_ERROR_NONE;
dvander@2168
   499
}
dvander@2168
   500
dvander@2168
   501
int CForward::PushFloatByRef(float *num, int flags)
dvander@2168
   502
{
dvander@2168
   503
	if (m_curparam < m_numparams)
dvander@2168
   504
	{
dvander@2168
   505
		if (m_types[m_curparam] == Param_Any)
dvander@2168
   506
		{
dvander@2168
   507
			m_params[m_curparam].pushedas = Param_FloatByRef;
dvander@2168
   508
		} else if (m_types[m_curparam] != Param_FloatByRef) {
dvander@2168
   509
			return SetError(SP_ERROR_PARAM);
dvander@2168
   510
		}
dvander@2168
   511
	} else {
dvander@2168
   512
		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
dvander@2168
   513
		{
dvander@2168
   514
			return SetError(SP_ERROR_PARAMS_MAX);
dvander@2168
   515
		}
dvander@2168
   516
		m_params[m_curparam].pushedas = Param_FloatByRef;
dvander@2168
   517
	}
dvander@2168
   518
dvander@2168
   519
	_Int_PushArray((cell_t *)num, 1, flags);
dvander@2168
   520
	m_curparam++;
dvander@2168
   521
dvander@2168
   522
	return SP_ERROR_NONE;
dvander@2168
   523
}
dvander@2168
   524
dvander@2168
   525
void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags)
dvander@2168
   526
{
dvander@2168
   527
	m_params[m_curparam].byref.cells = cells;
dvander@2168
   528
	m_params[m_curparam].byref.flags = flags;
dvander@2168
   529
	m_params[m_curparam].byref.orig_addr = inarray;
dvander@2168
   530
}
dvander@2168
   531
dvander@2168
   532
int CForward::PushArray(cell_t *inarray, unsigned int cells, int flags)
dvander@2168
   533
{
dvander@2168
   534
	/* We don't allow this here */
dvander@2168
   535
	if (!inarray)
dvander@2168
   536
	{
dvander@2168
   537
		return SetError(SP_ERROR_PARAM);
dvander@2168
   538
	}
dvander@2168
   539
dvander@2168
   540
	if (m_curparam < m_numparams)
dvander@2168
   541
	{
dvander@2168
   542
		if (m_types[m_curparam] == Param_Any)
dvander@2168
   543
		{
dvander@2168
   544
			m_params[m_curparam].pushedas = Param_Array;
dvander@2168
   545
		} else if (m_types[m_curparam] != Param_Array) {
dvander@2168
   546
			return SetError(SP_ERROR_PARAM);
dvander@2168
   547
		}
dvander@2168
   548
	} else {
dvander@2168
   549
		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
dvander@2168
   550
		{
dvander@2168
   551
			return SetError(SP_ERROR_PARAMS_MAX);
dvander@2168
   552
		}
dvander@2168
   553
		m_params[m_curparam].pushedas = Param_Array;
dvander@2168
   554
	}
dvander@2168
   555
dvander@2168
   556
	_Int_PushArray(inarray, cells, flags);
dvander@2168
   557
dvander@2168
   558
	m_curparam++;
dvander@2168
   559
dvander@2168
   560
	return SP_ERROR_NONE;
dvander@2168
   561
}
dvander@2168
   562
dvander@2168
   563
void CForward::_Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_flags)
dvander@2168
   564
{
dvander@2168
   565
	m_params[m_curparam].byref.cells = cells;	/* Notice this contains the char count not cell count */
dvander@2168
   566
	m_params[m_curparam].byref.flags = cp_flags;
dvander@2168
   567
	m_params[m_curparam].byref.orig_addr = inarray;
dvander@2168
   568
	m_params[m_curparam].byref.sz_flags = sz_flags;
dvander@2168
   569
}
dvander@2168
   570
dvander@2168
   571
int CForward::PushString(const char *string)
dvander@2168
   572
{
dvander@2168
   573
	if (m_curparam < m_numparams)
dvander@2168
   574
	{
dvander@2168
   575
		if (m_types[m_curparam] == Param_Any)
dvander@2168
   576
		{
dvander@2168
   577
			m_params[m_curparam].pushedas = Param_String;
dvander@2168
   578
		} else if (m_types[m_curparam] != Param_String) {
dvander@2168
   579
			return SetError(SP_ERROR_PARAM);
dvander@2168
   580
		}
dvander@2168
   581
	} else {
dvander@2168
   582
		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
dvander@2168
   583
		{
dvander@2168
   584
			return SetError(SP_ERROR_PARAMS_MAX);
dvander@2168
   585
		}
dvander@2168
   586
		m_params[m_curparam].pushedas = Param_String;
dvander@2168
   587
	}
dvander@2168
   588
dvander@2168
   589
	_Int_PushString((cell_t *)string, strlen(string)+1, SM_PARAM_STRING_COPY, 0);
dvander@2168
   590
	m_curparam++;
dvander@2168
   591
dvander@2168
   592
	return SP_ERROR_NONE;
dvander@2168
   593
}
dvander@2168
   594
dvander@2168
   595
int CForward::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
dvander@2168
   596
{
dvander@2168
   597
	if (m_curparam < m_numparams)
dvander@2168
   598
	{
dvander@2168
   599
		if (m_types[m_curparam] == Param_Any)
dvander@2168
   600
		{
dvander@2168
   601
			m_params[m_curparam].pushedas = Param_String;
dvander@2168
   602
		} else if (m_types[m_curparam] != Param_String) {
dvander@2168
   603
			return SetError(SP_ERROR_PARAM);
dvander@2168
   604
		}
dvander@2168
   605
	} else {
dvander@2168
   606
		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
dvander@2168
   607
		{
dvander@2168
   608
			return SetError(SP_ERROR_PARAMS_MAX);
dvander@2168
   609
		}
dvander@2168
   610
		m_params[m_curparam].pushedas = Param_String;
dvander@2168
   611
	}
dvander@2168
   612
dvander@2168
   613
	_Int_PushString((cell_t *)buffer, length, sz_flags, cp_flags);
dvander@2168
   614
	m_curparam++;
dvander@2168
   615
dvander@2168
   616
	return SP_ERROR_NONE;
dvander@2168
   617
}
dvander@2168
   618
dvander@2168
   619
void CForward::Cancel()
dvander@2168
   620
{
dvander@2168
   621
	if (!m_curparam)
dvander@2168
   622
	{
dvander@2168
   623
		return;
dvander@2168
   624
	}
dvander@2168
   625
dvander@2168
   626
	m_curparam = 0;
dvander@2168
   627
	m_errstate = SP_ERROR_NONE;
dvander@2168
   628
}
dvander@2168
   629
dvander@2168
   630
bool CForward::AddFunction(IPluginContext *pContext, funcid_t index)
dvander@2168
   631
{
dvander@2168
   632
	IPluginFunction *pFunc = pContext->GetFunctionById(index);
dvander@2168
   633
dvander@2168
   634
	if (!pFunc)
dvander@2168
   635
	{
dvander@2168
   636
		return false;
dvander@2168
   637
	}
dvander@2168
   638
dvander@2168
   639
	return AddFunction(pFunc);
dvander@2168
   640
}
dvander@2168
   641
dvander@2168
   642
bool CForward::RemoveFunction(IPluginContext *pContext, funcid_t index)
dvander@2168
   643
{
dvander@2168
   644
	IPluginFunction *pFunc = pContext->GetFunctionById(index);
dvander@2168
   645
dvander@2168
   646
	if (!pFunc)
dvander@2168
   647
	{
dvander@2168
   648
		return false;
dvander@2168
   649
	}
dvander@2168
   650
dvander@2168
   651
	return RemoveFunction(pFunc);
dvander@2168
   652
}
dvander@2168
   653
dvander@2168
   654
bool CForward::RemoveFunction(IPluginFunction *func)
dvander@2168
   655
{
dvander@2168
   656
	bool found = false;
dvander@2168
   657
	FuncIter iter;
dvander@2168
   658
	List<IPluginFunction *> *lst;
dvander@2168
   659
dvander@2168
   660
	if (func->IsRunnable())
dvander@2168
   661
	{
dvander@2168
   662
		lst = &m_functions;
dvander@2168
   663
	} else {
dvander@2168
   664
		lst = &m_paused;
dvander@2168
   665
	}
dvander@2168
   666
dvander@2168
   667
	for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
dvander@2168
   668
	{
dvander@2168
   669
		if ((*iter) == func)
dvander@2168
   670
		{
dvander@2168
   671
			found = true;
dvander@2168
   672
			lst->erase(iter);
dvander@2168
   673
			break;
dvander@2168
   674
		}
dvander@2168
   675
	}
dvander@2168
   676
dvander@2168
   677
	/* Cancel a call, if any */
dvander@2168
   678
	if (found || m_curparam)
dvander@2168
   679
	{
dvander@2168
   680
		func->Cancel();
dvander@2168
   681
	}
dvander@2168
   682
dvander@2168
   683
	return found;
dvander@2168
   684
}
dvander@2168
   685
dvander@2168
   686
unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin)
dvander@2168
   687
{
dvander@2168
   688
	FuncIter iter;
dvander@2168
   689
	IPluginFunction *func;
dvander@2168
   690
	unsigned int removed = 0;
dvander@2168
   691
	IPluginContext *pContext = plugin->GetBaseContext();
dvander@2168
   692
	for (iter=m_functions.begin(); iter!=m_functions.end();)
dvander@2168
   693
	{
dvander@2168
   694
		func = (*iter);
dvander@2168
   695
		if (func->GetParentContext() == pContext)
dvander@2168
   696
		{
dvander@2168
   697
			iter = m_functions.erase(iter);
dvander@2168
   698
			removed++;
dvander@2168
   699
		} else {
dvander@2168
   700
			iter++;
dvander@2168
   701
		}
dvander@2168
   702
	}
dvander@2168
   703
dvander@2168
   704
	return removed;
dvander@2168
   705
}
dvander@2168
   706
dvander@2168
   707
bool CForward::AddFunction(IPluginFunction *func)
dvander@2168
   708
{
dvander@2168
   709
	if (m_curparam)
dvander@2168
   710
	{
dvander@2168
   711
		return false;
dvander@2168
   712
	}
dvander@2168
   713
dvander@2168
   714
	if (func->IsRunnable())
dvander@2168
   715
	{
dvander@2168
   716
		m_functions.push_back(func);
dvander@2168
   717
	} else {
dvander@2168
   718
		m_paused.push_back(func);
dvander@2168
   719
	}
dvander@2168
   720
dvander@2168
   721
	return true;
dvander@2168
   722
}
dvander@2168
   723
dvander@2168
   724
const char *CForward::GetForwardName()
dvander@2168
   725
{
dvander@2168
   726
	return m_name;
dvander@2168
   727
}
dvander@2168
   728
dvander@2168
   729
unsigned int CForward::GetFunctionCount()
dvander@2168
   730
{
dvander@2168
   731
	return m_functions.size();
dvander@2168
   732
}
dvander@2168
   733
dvander@2168
   734
ExecType CForward::GetExecType()
dvander@2168
   735
{
dvander@2168
   736
	return m_ExecType;
dvander@2168
   737
}