ds@730: /** dvander@2883: * vim: set ts=4 sw=4 tw=99 noet : ds@1330: * ============================================================================= dvander@1231: * SourceMod ds@1947: * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. ds@1330: * ============================================================================= dvander@370: * ds@1330: * This program is free software; you can redistribute it and/or modify it under ds@1330: * the terms of the GNU General Public License, version 3.0, as published by the ds@1330: * Free Software Foundation. dvander@1231: * ds@1330: * This program is distributed in the hope that it will be useful, but WITHOUT ds@1330: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ds@1330: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ds@1330: * details. dvander@1231: * ds@1330: * You should have received a copy of the GNU General Public License along with ds@1330: * this program. If not, see . dvander@1231: * ds@1330: * As a special exception, AlliedModders LLC gives you permission to link the ds@1330: * code of this program (as well as its derivative works) to "Half-Life 2," the ds@1330: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software ds@1330: * by the Valve Corporation. You must obey the GNU General Public License in ds@1330: * all respects for all other code used. Additionally, AlliedModders LLC grants ds@1330: * this exception to all derivative works. AlliedModders LLC defines further ds@1330: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), ds@1330: * or . dvander@370: * dvander@370: * Version: $Id$ dvander@370: */ dvander@370: dvander@180: #include dvander@351: #include dvander@351: #include dvander@180: #include "ForwardSys.h" dvander@3792: #include "logic_bridge.h" dvander@180: dvander@186: CForwardManager g_Forwards; dvander@186: dvander@183: /** ds@729: * Genesis turns to its source, reduction occurs stepwise although the essence is all one. dvander@183: * End of line. FTL system check. dvander@183: * dvander@282: * :TODO: WHAT NEEDS TO BE TESTED IN THIS BEAST dvander@183: * VARARG FUNCTIONS: dvander@183: * - Pushing no varargs dvander@183: */ dvander@183: faluco@226: // :TODO: IMPORTANT!!! The result pointer arg in the execute function maybe invalid if the forward fails faluco@226: // so later evaluation of this result may cause problems on higher levels of abstraction. DOCUMENT OR FIX ALL FORWARDS! faluco@226: faluco@641: CForwardManager::~CForwardManager() faluco@641: { faluco@641: CStack::iterator iter; faluco@641: for (iter=m_FreeForwards.begin(); iter!=m_FreeForwards.end(); iter++) faluco@641: { faluco@641: delete (*iter); faluco@641: } faluco@641: m_FreeForwards.popall(); faluco@641: } faluco@641: dvander@211: void CForwardManager::OnSourceModAllInitialized() dvander@211: { dvander@3872: scripts->AddPluginsListener(this); dvander@3872: sharesys->AddInterface(NULL, this); dvander@211: } dvander@211: ds@559: IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned int num_params, const ParamType *types, ...) dvander@186: { dvander@186: CForward *fwd; dvander@186: va_list ap; dvander@186: va_start(ap, types); dvander@186: dvander@186: fwd = CForward::CreateForward(name, et, num_params, types, ap); dvander@186: dvander@186: va_end(ap); dvander@186: dvander@211: if (fwd) dvander@211: { dvander@3872: scripts->AddFunctionsToForward(name, fwd); ds@611: dvander@211: m_managed.push_back(fwd); dvander@211: } dvander@211: dvander@186: return fwd; dvander@186: } dvander@186: ds@559: IChangeableForward *CForwardManager::CreateForwardEx(const char *name, ExecType et, int num_params, const ParamType *types, ...) dvander@186: { dvander@186: CForward *fwd; dvander@186: va_list ap; dvander@186: va_start(ap, types); dvander@186: dvander@186: fwd = CForward::CreateForward(name, et, num_params, types, ap); dvander@186: dvander@186: va_end(ap); dvander@186: dvander@211: if (fwd) dvander@211: { dvander@211: m_unmanaged.push_back(fwd); dvander@211: } dvander@211: dvander@186: return fwd; dvander@186: } dvander@186: dvander@211: void CForwardManager::OnPluginLoaded(IPlugin *plugin) dvander@211: { dvander@211: /* Attach any globally managed forwards */ dvander@211: List::iterator iter; dvander@211: CForward *fwd; dvander@211: dvander@211: for (iter=m_managed.begin(); iter!=m_managed.end(); iter++) dvander@211: { dvander@211: fwd = (*iter); dvander@327: IPluginFunction *pFunc = plugin->GetBaseContext()->GetFunctionByName(fwd->GetForwardName()); dvander@211: if (pFunc) dvander@211: { dvander@211: fwd->AddFunction(pFunc); dvander@211: } dvander@211: } dvander@211: } dvander@211: dvander@211: void CForwardManager::OnPluginUnloaded(IPlugin *plugin) dvander@211: { dvander@211: List::iterator iter; dvander@211: CForward *fwd; dvander@211: dvander@211: for (iter=m_managed.begin(); iter!=m_managed.end(); iter++) dvander@211: { dvander@211: fwd = (*iter); dvander@211: fwd->RemoveFunctionsOfPlugin(plugin); dvander@211: } dvander@232: dvander@232: for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++) dvander@232: { dvander@232: fwd = (*iter); dvander@232: fwd->RemoveFunctionsOfPlugin(plugin); dvander@232: } dvander@211: } dvander@211: dvander@186: IForward *CForwardManager::FindForward(const char *name, IChangeableForward **ifchng) dvander@186: { dvander@186: List::iterator iter; dvander@186: CForward *fwd; dvander@186: dvander@186: for (iter=m_managed.begin(); iter!=m_managed.end(); iter++) dvander@186: { dvander@186: fwd = (*iter); dvander@186: if (strcmp(fwd->GetForwardName(), name) == 0) dvander@186: { dvander@186: if (ifchng) dvander@186: { dvander@186: *ifchng = NULL; dvander@186: } dvander@186: return fwd; dvander@186: } dvander@186: } dvander@186: dvander@186: for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++) dvander@186: { dvander@186: fwd = (*iter); dvander@186: if (strcmp(fwd->GetForwardName(), name) == 0) dvander@186: { dvander@186: if (ifchng) dvander@186: { dvander@186: *ifchng = fwd; dvander@186: } dvander@186: return fwd; dvander@186: } dvander@186: } dvander@186: dvander@186: if (ifchng) dvander@186: { dvander@186: *ifchng = NULL; dvander@186: } dvander@186: dvander@186: return NULL; dvander@186: } dvander@186: dvander@186: void CForwardManager::ReleaseForward(IForward *forward) dvander@186: { dvander@186: ForwardFree(static_cast(forward)); dvander@186: } dvander@186: dvander@186: void CForwardManager::ForwardFree(CForward *fwd) dvander@186: { dvander@2234: if (fwd == NULL) dvander@2234: { dvander@2234: return; dvander@2234: } dvander@2234: dvander@186: m_FreeForwards.push(fwd); faluco@291: m_managed.remove(fwd); dvander@186: } dvander@186: dvander@186: CForward *CForwardManager::ForwardMake() dvander@186: { dvander@186: CForward *fwd; dvander@186: if (m_FreeForwards.empty()) dvander@186: { dvander@186: fwd = new CForward; dvander@186: } else { dvander@186: fwd = m_FreeForwards.front(); dvander@186: m_FreeForwards.pop(); dvander@186: } dvander@186: return fwd; dvander@186: } dvander@186: faluco@430: void CForwardManager::OnPluginPauseChange(IPlugin *plugin, bool paused) faluco@430: { dvander@526: /* No longer used */ faluco@430: } faluco@430: dvander@186: /************************************* dvander@186: * ACTUAL FORWARD API IMPLEMENTATION * dvander@186: *************************************/ dvander@186: ds@559: CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int num_params, const ParamType *types, va_list ap) dvander@180: { dvander@180: ParamType _types[SP_MAX_EXEC_PARAMS]; dvander@180: dvander@180: if (num_params > SP_MAX_EXEC_PARAMS) dvander@180: { dvander@180: return NULL; dvander@180: } dvander@180: dvander@180: if (types == NULL && num_params) dvander@180: { dvander@180: for (unsigned int i=0; im_IterGuard = NULL; dvander@180: pForward->m_curparam = 0; dvander@180: pForward->m_ExecType = et; dvander@180: snprintf(pForward->m_name, FORWARDS_NAME_MAX, "%s", name ? name : ""); dvander@180: dvander@180: for (unsigned int i=0; im_types[i] = _types[i]; dvander@180: } dvander@180: dvander@529: if (num_params && _types[num_params-1] == Param_VarArgs) dvander@180: { dvander@183: pForward->m_varargs = num_params--; dvander@180: } else { dvander@180: pForward->m_varargs = false; dvander@180: } dvander@180: dvander@180: pForward->m_numparams = num_params; dvander@180: pForward->m_errstate = SP_ERROR_NONE; dvander@180: dvander@961: pForward->m_functions.clear(); dvander@961: dvander@180: return pForward; dvander@180: } dvander@180: dvander@180: int CForward::Execute(cell_t *result, IForwardFilter *filter) dvander@180: { dvander@180: if (m_errstate) dvander@180: { dvander@180: int err = m_errstate; dvander@180: Cancel(); dvander@180: return err; dvander@180: } dvander@180: dvander@180: FuncIter iter = m_functions.begin(); dvander@180: IPluginFunction *func; dvander@180: cell_t cur_result = 0; dvander@180: cell_t high_result = 0; ds@2181: cell_t low_result = 0; dvander@180: int err; dvander@2890: unsigned int success=0; dvander@183: unsigned int num_params = m_curparam; dvander@183: FwdParamInfo temp_info[SP_MAX_EXEC_PARAMS]; dvander@183: FwdParamInfo *param; dvander@183: ParamType type; dvander@180: dvander@183: /* Save local, reset */ dvander@183: memcpy(temp_info, m_params, sizeof(m_params)); dvander@183: m_curparam = 0; dvander@183: dvander@2890: FuncIteratorGuard guard(&m_IterGuard, &iter); dvander@2890: dvander@2890: while (iter != m_functions.end()) dvander@180: { dvander@180: func = (*iter); dvander@183: dvander@2883: if (filter) dvander@2883: filter->Preprocess(func, temp_info); dvander@2883: dvander@183: for (unsigned int i=0; i= m_numparams || m_types[i] == Param_Any) dvander@183: { dvander@183: type = param->pushedas; ds@2181: } ds@2181: else ds@2181: { dvander@183: type = m_types[i]; dvander@183: } ds@2181: dvander@183: if ((i >= m_numparams) || (type & SP_PARAMFLAG_BYREF)) dvander@180: { dvander@183: /* If we're byref or we're vararg, we always push everything by ref. dvander@183: * Even if they're byval, we must push them byref. dvander@183: */ faluco@192: if (type == Param_String) dvander@180: { dvander@1339: err = func->PushStringEx((char *)param->byref.orig_addr, param->byref.cells, param->byref.sz_flags, param->byref.flags); ds@2181: } ds@2181: else if (type == Param_Float || type == Param_Cell) ds@2181: { dvander@1339: err = func->PushCellByRef(¶m->val); ds@2181: } ds@2181: else ds@2181: { dvander@1339: err = func->PushArray(param->byref.orig_addr, param->byref.cells, param->byref.flags); dvander@183: assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef); dvander@180: } ds@2181: } ds@2181: else ds@2181: { dvander@183: /* If we're not byref or not vararg, our job is a bit easier. */ dvander@183: assert(type == Param_Cell || type == Param_Float); dvander@1339: err = func->PushCell(param->val); dvander@1339: } ds@2181: dvander@1339: if (err != SP_ERROR_NONE) dvander@1339: { dvander@3792: logicore.GenerateError(func->GetParentContext(), ds@2181: func->GetFunctionID(), ds@2181: err, ds@2181: "Failed to push parameter while executing forward"); dvander@1339: continue; dvander@180: } dvander@180: } dvander@183: dvander@211: /* Call the function and deal with the return value. */ dvander@2890: if ((err=func->Execute(&cur_result)) == SP_ERROR_NONE) ds@2181: { dvander@180: success++; dvander@180: switch (m_ExecType) dvander@180: { dvander@180: case ET_Event: dvander@180: { dvander@180: if (cur_result > high_result) dvander@180: { dvander@180: high_result = cur_result; dvander@180: } dvander@180: break; dvander@180: } dvander@180: case ET_Hook: dvander@180: { dvander@180: if (cur_result > high_result) dvander@180: { dvander@180: high_result = cur_result; dvander@180: if ((ResultType)high_result == Pl_Stop) dvander@180: { ds@1140: goto done; dvander@180: } dvander@180: } dvander@180: break; dvander@180: } ds@2181: case ET_LowEvent: dvander@180: { pred@2183: /* Check if the current result is the lowest so far (or if it's the first result) */ pred@2183: if (cur_result < low_result || success == 1) dvander@180: { ds@2181: low_result = cur_result; dvander@180: } dvander@180: break; dvander@180: } dvander@351: default: dvander@351: { dvander@351: break; dvander@351: } dvander@180: } dvander@180: } dvander@2890: dvander@2890: if (!guard.Triggered()) dvander@2890: iter++; dvander@180: } dvander@180: ds@1140: done: ds@2181: dvander@447: if (success) dvander@180: { ds@2181: switch (m_ExecType) dvander@447: { ds@2181: case ET_Ignore: ds@2181: { ds@2181: cur_result = 0; ds@2181: break; ds@2181: } ds@2181: case ET_Event: ds@2181: case ET_Hook: ds@2181: { ds@2181: cur_result = high_result; ds@2181: break; ds@2181: } ds@2181: case ET_LowEvent: ds@2181: { ds@2181: cur_result = low_result; ds@2181: break; ds@2181: } ds@2181: default: ds@2181: { ds@2181: break; ds@2181: } dvander@447: } ds@2181: dvander@447: if (result) dvander@447: { dvander@447: *result = cur_result; dvander@447: } dvander@180: } dvander@180: dvander@180: return SP_ERROR_NONE; dvander@180: } dvander@180: dvander@180: int CForward::PushCell(cell_t cell) dvander@180: { dvander@180: if (m_curparam < m_numparams) dvander@180: { dvander@183: if (m_types[m_curparam] == Param_Any) dvander@180: { dvander@183: m_params[m_curparam].pushedas = Param_Cell; dvander@183: } else if (m_types[m_curparam] != Param_Cell) { dvander@180: return SetError(SP_ERROR_PARAM); dvander@180: } dvander@180: } else { dvander@180: if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS) dvander@180: { dvander@180: return SetError(SP_ERROR_PARAMS_MAX); dvander@180: } dvander@183: m_params[m_curparam].pushedas = Param_Cell; dvander@180: } dvander@180: dvander@183: m_params[m_curparam++].val = cell; dvander@180: dvander@180: return SP_ERROR_NONE; dvander@180: } dvander@180: dvander@180: int CForward::PushFloat(float number) dvander@180: { dvander@180: if (m_curparam < m_numparams) dvander@180: { dvander@183: if (m_types[m_curparam] == Param_Any) dvander@180: { dvander@183: m_params[m_curparam].pushedas = Param_Float; dvander@183: } else if (m_types[m_curparam] != Param_Float) { dvander@180: return SetError(SP_ERROR_PARAM); dvander@180: } dvander@180: } else { dvander@180: if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS) dvander@180: { dvander@180: return SetError(SP_ERROR_PARAMS_MAX); dvander@180: } dvander@183: m_params[m_curparam].pushedas = Param_Float; dvander@180: } dvander@180: dvander@183: m_params[m_curparam++].val = *(cell_t *)&number; dvander@180: dvander@180: return SP_ERROR_NONE; dvander@180: } dvander@180: ds@585: int CForward::PushCellByRef(cell_t *cell, int flags) dvander@180: { dvander@180: if (m_curparam < m_numparams) dvander@180: { faluco@192: if (m_types[m_curparam] == Param_Any) dvander@180: { faluco@192: m_params[m_curparam].pushedas = Param_CellByRef; faluco@192: } else if (m_types[m_curparam] != Param_CellByRef) { dvander@180: return SetError(SP_ERROR_PARAM); dvander@180: } dvander@180: } else { dvander@180: if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS) dvander@180: { dvander@180: return SetError(SP_ERROR_PARAMS_MAX); dvander@180: } faluco@192: m_params[m_curparam].pushedas = Param_CellByRef; dvander@180: } dvander@180: ds@585: _Int_PushArray(cell, 1, flags); dvander@180: m_curparam++; dvander@180: dvander@180: return SP_ERROR_NONE; dvander@180: } dvander@180: ds@585: int CForward::PushFloatByRef(float *num, int flags) dvander@180: { dvander@180: if (m_curparam < m_numparams) dvander@180: { faluco@192: if (m_types[m_curparam] == Param_Any) dvander@180: { faluco@192: m_params[m_curparam].pushedas = Param_FloatByRef; faluco@192: } else if (m_types[m_curparam] != Param_FloatByRef) { dvander@180: return SetError(SP_ERROR_PARAM); dvander@180: } dvander@180: } else { dvander@180: if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS) dvander@180: { dvander@180: return SetError(SP_ERROR_PARAMS_MAX); dvander@180: } faluco@192: m_params[m_curparam].pushedas = Param_FloatByRef; dvander@180: } dvander@180: ds@585: _Int_PushArray((cell_t *)num, 1, flags); dvander@180: m_curparam++; dvander@180: dvander@180: return SP_ERROR_NONE; dvander@180: } dvander@180: dvander@180: void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags) dvander@180: { dvander@183: m_params[m_curparam].byref.cells = cells; dvander@183: m_params[m_curparam].byref.flags = flags; dvander@183: m_params[m_curparam].byref.orig_addr = inarray; dvander@180: } dvander@180: dvander@589: int CForward::PushArray(cell_t *inarray, unsigned int cells, int flags) dvander@180: { dvander@180: /* We don't allow this here */ dvander@180: if (!inarray) dvander@180: { dvander@180: return SetError(SP_ERROR_PARAM); dvander@180: } dvander@180: dvander@180: if (m_curparam < m_numparams) dvander@180: { dvander@183: if (m_types[m_curparam] == Param_Any) dvander@180: { dvander@183: m_params[m_curparam].pushedas = Param_Array; dvander@183: } else if (m_types[m_curparam] != Param_Array) { dvander@180: return SetError(SP_ERROR_PARAM); dvander@180: } dvander@180: } else { dvander@180: if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS) dvander@180: { dvander@180: return SetError(SP_ERROR_PARAMS_MAX); dvander@180: } dvander@183: m_params[m_curparam].pushedas = Param_Array; dvander@180: } dvander@180: dvander@180: _Int_PushArray(inarray, cells, flags); dvander@180: dvander@180: m_curparam++; dvander@180: dvander@180: return SP_ERROR_NONE; dvander@180: } dvander@180: faluco@192: void CForward::_Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_flags) faluco@192: { faluco@192: m_params[m_curparam].byref.cells = cells; /* Notice this contains the char count not cell count */ faluco@192: m_params[m_curparam].byref.flags = cp_flags; faluco@192: m_params[m_curparam].byref.orig_addr = inarray; faluco@192: m_params[m_curparam].byref.sz_flags = sz_flags; faluco@192: } faluco@192: dvander@180: int CForward::PushString(const char *string) dvander@180: { dvander@180: if (m_curparam < m_numparams) dvander@180: { dvander@183: if (m_types[m_curparam] == Param_Any) dvander@180: { dvander@183: m_params[m_curparam].pushedas = Param_String; faluco@188: } else if (m_types[m_curparam] != Param_String) { dvander@180: return SetError(SP_ERROR_PARAM); dvander@180: } dvander@180: } else { dvander@180: if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS) dvander@180: { dvander@180: return SetError(SP_ERROR_PARAMS_MAX); dvander@180: } dvander@183: m_params[m_curparam].pushedas = Param_String; dvander@180: } dvander@180: dvander@211: _Int_PushString((cell_t *)string, strlen(string)+1, SM_PARAM_STRING_COPY, 0); dvander@180: m_curparam++; dvander@180: dvander@180: return SP_ERROR_NONE; dvander@180: } dvander@180: faluco@192: int CForward::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags) dvander@180: { dvander@180: if (m_curparam < m_numparams) dvander@180: { dvander@183: if (m_types[m_curparam] == Param_Any) dvander@180: { dvander@183: m_params[m_curparam].pushedas = Param_String; faluco@188: } else if (m_types[m_curparam] != Param_String) { dvander@180: return SetError(SP_ERROR_PARAM); dvander@180: } dvander@180: } else { dvander@180: if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS) dvander@180: { dvander@180: return SetError(SP_ERROR_PARAMS_MAX); dvander@180: } dvander@183: m_params[m_curparam].pushedas = Param_String; dvander@180: } dvander@180: faluco@192: _Int_PushString((cell_t *)buffer, length, sz_flags, cp_flags); dvander@180: m_curparam++; dvander@180: dvander@180: return SP_ERROR_NONE; dvander@180: } dvander@180: dvander@180: void CForward::Cancel() dvander@180: { dvander@180: if (!m_curparam) dvander@180: { dvander@180: return; dvander@180: } dvander@180: dvander@183: m_curparam = 0; dvander@180: m_errstate = SP_ERROR_NONE; dvander@180: } dvander@180: dvander@327: bool CForward::AddFunction(IPluginContext *pContext, funcid_t index) dvander@180: { dvander@327: IPluginFunction *pFunc = pContext->GetFunctionById(index); dvander@180: dvander@180: if (!pFunc) dvander@180: { dvander@180: return false; dvander@180: } dvander@180: dvander@180: return AddFunction(pFunc); dvander@180: } dvander@180: ds@621: bool CForward::RemoveFunction(IPluginContext *pContext, funcid_t index) ds@621: { ds@621: IPluginFunction *pFunc = pContext->GetFunctionById(index); ds@621: ds@621: if (!pFunc) ds@621: { ds@621: return false; ds@621: } ds@621: ds@621: return RemoveFunction(pFunc); ds@621: } ds@621: dvander@180: bool CForward::RemoveFunction(IPluginFunction *func) dvander@180: { dvander@180: bool found = false; dvander@180: FuncIter iter; dvander@527: List *lst; dvander@527: dvander@527: if (func->IsRunnable()) dvander@527: { dvander@527: lst = &m_functions; dvander@527: } else { dvander@527: lst = &m_paused; dvander@527: } dvander@180: dvander@525: for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) dvander@180: { dvander@180: if ((*iter) == func) dvander@180: { dvander@2890: m_IterGuard->FixIteratorChain(iter); dvander@180: found = true; dvander@527: lst->erase(iter); faluco@430: break; dvander@180: } dvander@180: } dvander@180: dvander@180: /* Cancel a call, if any */ dvander@183: if (found || m_curparam) dvander@180: { dvander@180: func->Cancel(); dvander@180: } dvander@180: dvander@180: return found; dvander@180: } dvander@180: dvander@180: unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin) dvander@180: { dvander@180: FuncIter iter; dvander@180: IPluginFunction *func; dvander@180: unsigned int removed = 0; dvander@327: IPluginContext *pContext = plugin->GetBaseContext(); dvander@180: for (iter=m_functions.begin(); iter!=m_functions.end();) dvander@180: { dvander@180: func = (*iter); dvander@327: if (func->GetParentContext() == pContext) dvander@180: { dvander@180: iter = m_functions.erase(iter); dvander@180: removed++; dvander@180: } else { dvander@180: iter++; dvander@180: } dvander@180: } dvander@180: dvander@180: return removed; dvander@180: } dvander@180: dvander@180: bool CForward::AddFunction(IPluginFunction *func) dvander@180: { dvander@180: if (m_curparam) dvander@180: { dvander@180: return false; dvander@180: } dvander@180: dvander@527: if (func->IsRunnable()) dvander@527: { dvander@527: m_functions.push_back(func); dvander@527: } else { dvander@527: m_paused.push_back(func); dvander@527: } dvander@180: dvander@180: return true; dvander@180: } dvander@180: dvander@615: const char *CForward::GetForwardName() dvander@180: { dvander@180: return m_name; dvander@180: } dvander@180: dvander@615: unsigned int CForward::GetFunctionCount() dvander@180: { dvander@180: return m_functions.size(); dvander@180: } dvander@180: dvander@615: ExecType CForward::GetExecType() dvander@180: { dvander@180: return m_ExecType; dvander@180: }