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