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