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