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