3 * ===============================================================
4 * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
5 * ===============================================================
7 * This file is not open source and may not be copied without explicit
8 * written permission of AlliedModders LLC. This file may not be redistributed
9 * in whole or significant part.
10 * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
18 #include "ForwardSys.h"
19 #include "PluginSys.h"
22 CForwardManager g_Forwards;
25 * Genesis turns to its source, reduction occurs stepwise although the essence is all one.
26 * End of line. FTL system check.
28 * :TODO: WHAT NEEDS TO BE TESTED IN THIS BEAST
30 * - Pushing no varargs
33 // :TODO: IMPORTANT!!! The result pointer arg in the execute function maybe invalid if the forward fails
34 // so later evaluation of this result may cause problems on higher levels of abstraction. DOCUMENT OR FIX ALL FORWARDS!
36 CForwardManager::~CForwardManager()
38 CStack<CForward *>::iterator iter;
39 for (iter=m_FreeForwards.begin(); iter!=m_FreeForwards.end(); iter++)
43 m_FreeForwards.popall();
46 void CForwardManager::OnSourceModAllInitialized()
48 g_PluginSys.AddPluginsListener(this);
49 g_ShareSys.AddInterface(NULL, this);
52 IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned int num_params, const ParamType *types, ...)
58 fwd = CForward::CreateForward(name, et, num_params, types, ap);
64 g_PluginSys.AddFunctionsToForward(name, fwd);
66 m_managed.push_back(fwd);
72 IChangeableForward *CForwardManager::CreateForwardEx(const char *name, ExecType et, int num_params, const ParamType *types, ...)
78 fwd = CForward::CreateForward(name, et, num_params, types, ap);
84 m_unmanaged.push_back(fwd);
90 void CForwardManager::OnPluginLoaded(IPlugin *plugin)
92 /* Attach any globally managed forwards */
93 List<CForward *>::iterator iter;
96 for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
99 IPluginFunction *pFunc = plugin->GetBaseContext()->GetFunctionByName(fwd->GetForwardName());
102 fwd->AddFunction(pFunc);
107 void CForwardManager::OnPluginUnloaded(IPlugin *plugin)
109 List<CForward *>::iterator iter;
112 for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
115 fwd->RemoveFunctionsOfPlugin(plugin);
118 for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
121 fwd->RemoveFunctionsOfPlugin(plugin);
125 IForward *CForwardManager::FindForward(const char *name, IChangeableForward **ifchng)
127 List<CForward *>::iterator iter;
130 for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
133 if (strcmp(fwd->GetForwardName(), name) == 0)
143 for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
146 if (strcmp(fwd->GetForwardName(), name) == 0)
164 void CForwardManager::ReleaseForward(IForward *forward)
166 ForwardFree(static_cast<CForward *>(forward));
169 void CForwardManager::ForwardFree(CForward *fwd)
171 m_FreeForwards.push(fwd);
172 m_managed.remove(fwd);
175 CForward *CForwardManager::ForwardMake()
178 if (m_FreeForwards.empty())
182 fwd = m_FreeForwards.front();
183 m_FreeForwards.pop();
188 void CForwardManager::OnPluginPauseChange(IPlugin *plugin, bool paused)
193 /*************************************
194 * ACTUAL FORWARD API IMPLEMENTATION *
195 *************************************/
197 CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int num_params, const ParamType *types, va_list ap)
199 ParamType _types[SP_MAX_EXEC_PARAMS];
201 if (num_params > SP_MAX_EXEC_PARAMS)
206 if (types == NULL && num_params)
208 for (unsigned int i=0; i<num_params; i++)
210 _types[i] = (ParamType)va_arg(ap, int);
211 if (_types[i] == Param_VarArgs && (i != num_params - 1))
218 for (unsigned int i=0; i<num_params; i++)
220 _types[i] = types[i];
221 if (types[i] == Param_VarArgs && (i != num_params - 1))
228 /* First parameter can never be varargs */
229 if (num_params && _types[0] == Param_VarArgs)
234 CForward *pForward = g_Forwards.ForwardMake();
235 pForward->m_curparam = 0;
236 pForward->m_ExecType = et;
237 snprintf(pForward->m_name, FORWARDS_NAME_MAX, "%s", name ? name : "");
239 for (unsigned int i=0; i<num_params; i++)
241 pForward->m_types[i] = _types[i];
244 if (num_params && _types[num_params-1] == Param_VarArgs)
246 pForward->m_varargs = num_params--;
248 pForward->m_varargs = false;
251 pForward->m_numparams = num_params;
252 pForward->m_errstate = SP_ERROR_NONE;
254 pForward->m_functions.clear();
259 int CForward::Execute(cell_t *result, IForwardFilter *filter)
263 int err = m_errstate;
270 filter->OnExecuteBegin();
273 FuncIter iter = m_functions.begin();
274 IPluginFunction *func;
275 cell_t cur_result = 0;
276 cell_t high_result = 0;
278 unsigned int failed=0, success=0;
279 unsigned int num_params = m_curparam;
280 FwdParamInfo temp_info[SP_MAX_EXEC_PARAMS];
284 /* Save local, reset */
285 memcpy(temp_info, m_params, sizeof(m_params));
288 for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
292 for (unsigned int i=0; i<num_params; i++)
294 param = &temp_info[i];
295 if (i >= m_numparams || m_types[i] == Param_Any)
297 type = param->pushedas;
301 if ((i >= m_numparams) || (type & SP_PARAMFLAG_BYREF))
303 /* If we're byref or we're vararg, we always push everything by ref.
304 * Even if they're byval, we must push them byref.
306 if (type == Param_String)
308 func->PushStringEx((char *)param->byref.orig_addr, param->byref.cells, param->byref.sz_flags, param->byref.flags);
309 } else if (type == Param_Float || type == Param_Cell) {
310 func->PushCellByRef(¶m->val);
312 func->PushArray(param->byref.orig_addr, param->byref.cells, param->byref.flags);
313 assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef);
316 /* If we're not byref or not vararg, our job is a bit easier. */
317 assert(type == Param_Cell || type == Param_Float);
318 func->PushCell(param->val);
322 /* Call the function and deal with the return value. */
323 if ((err=func->Execute(&cur_result)) != SP_ERROR_NONE)
325 bool handled = false;
328 handled = filter->OnErrorReport(this, func, err);
332 /* :TODO: invoke global error reporting here */
341 if (cur_result > high_result)
343 high_result = cur_result;
349 if (cur_result > high_result)
351 high_result = cur_result;
352 if ((ResultType)high_result == Pl_Stop)
354 iter = m_functions.end();
364 if (filter->OnFunctionReturn(this, func, &cur_result) == Pl_Stop)
366 iter = m_functions.end();
381 if (m_ExecType == ET_Event || m_ExecType == ET_Hook)
383 cur_result = high_result;
384 } else if (m_ExecType == ET_Ignore) {
389 *result = cur_result;
395 filter->OnExecuteEnd(&cur_result, success, failed);
398 return SP_ERROR_NONE;
401 int CForward::PushCell(cell_t cell)
403 if (m_curparam < m_numparams)
405 if (m_types[m_curparam] == Param_Any)
407 m_params[m_curparam].pushedas = Param_Cell;
408 } else if (m_types[m_curparam] != Param_Cell) {
409 return SetError(SP_ERROR_PARAM);
412 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
414 return SetError(SP_ERROR_PARAMS_MAX);
416 m_params[m_curparam].pushedas = Param_Cell;
419 m_params[m_curparam++].val = cell;
421 return SP_ERROR_NONE;
424 int CForward::PushFloat(float number)
426 if (m_curparam < m_numparams)
428 if (m_types[m_curparam] == Param_Any)
430 m_params[m_curparam].pushedas = Param_Float;
431 } else if (m_types[m_curparam] != Param_Float) {
432 return SetError(SP_ERROR_PARAM);
435 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
437 return SetError(SP_ERROR_PARAMS_MAX);
439 m_params[m_curparam].pushedas = Param_Float;
442 m_params[m_curparam++].val = *(cell_t *)&number;
444 return SP_ERROR_NONE;
447 int CForward::PushCellByRef(cell_t *cell, int flags)
449 if (m_curparam < m_numparams)
451 if (m_types[m_curparam] == Param_Any)
453 m_params[m_curparam].pushedas = Param_CellByRef;
454 } else if (m_types[m_curparam] != Param_CellByRef) {
455 return SetError(SP_ERROR_PARAM);
458 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
460 return SetError(SP_ERROR_PARAMS_MAX);
462 m_params[m_curparam].pushedas = Param_CellByRef;
465 _Int_PushArray(cell, 1, flags);
468 return SP_ERROR_NONE;
471 int CForward::PushFloatByRef(float *num, int flags)
473 if (m_curparam < m_numparams)
475 if (m_types[m_curparam] == Param_Any)
477 m_params[m_curparam].pushedas = Param_FloatByRef;
478 } else if (m_types[m_curparam] != Param_FloatByRef) {
479 return SetError(SP_ERROR_PARAM);
482 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
484 return SetError(SP_ERROR_PARAMS_MAX);
486 m_params[m_curparam].pushedas = Param_FloatByRef;
489 _Int_PushArray((cell_t *)num, 1, flags);
492 return SP_ERROR_NONE;
495 void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags)
497 m_params[m_curparam].byref.cells = cells;
498 m_params[m_curparam].byref.flags = flags;
499 m_params[m_curparam].byref.orig_addr = inarray;
502 int CForward::PushArray(cell_t *inarray, unsigned int cells, int flags)
504 /* We don't allow this here */
507 return SetError(SP_ERROR_PARAM);
510 if (m_curparam < m_numparams)
512 if (m_types[m_curparam] == Param_Any)
514 m_params[m_curparam].pushedas = Param_Array;
515 } else if (m_types[m_curparam] != Param_Array) {
516 return SetError(SP_ERROR_PARAM);
519 if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
521 return SetError(SP_ERROR_PARAMS_MAX);
523 m_params[m_curparam].pushedas = Param_Array;
526 _Int_PushArray(inarray, cells, flags);
530 return SP_ERROR_NONE;
533 void CForward::_Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_flags)
535 m_params[m_curparam].byref.cells = cells; /* Notice this contains the char count not cell count */
536 m_params[m_curparam].byref.flags = cp_flags;
537 m_params[m_curparam].byref.orig_addr = inarray;
538 m_params[m_curparam].byref.sz_flags = sz_flags;
541 int CForward::PushString(const char *string)
543 if (m_curparam < m_numparams)
545 if (m_types[m_curparam] == Param_Any)
547 m_params[m_curparam].pushedas = Param_String;
548 } else if (m_types[m_curparam] != Param_String) {
549 return SetError(SP_ERROR_PARAM);
552 if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
554 return SetError(SP_ERROR_PARAMS_MAX);
556 m_params[m_curparam].pushedas = Param_String;
559 _Int_PushString((cell_t *)string, strlen(string)+1, SM_PARAM_STRING_COPY, 0);
562 return SP_ERROR_NONE;
565 int CForward::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
567 if (m_curparam < m_numparams)
569 if (m_types[m_curparam] == Param_Any)
571 m_params[m_curparam].pushedas = Param_String;
572 } else if (m_types[m_curparam] != Param_String) {
573 return SetError(SP_ERROR_PARAM);
576 if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
578 return SetError(SP_ERROR_PARAMS_MAX);
580 m_params[m_curparam].pushedas = Param_String;
583 _Int_PushString((cell_t *)buffer, length, sz_flags, cp_flags);
586 return SP_ERROR_NONE;
589 void CForward::Cancel()
597 m_errstate = SP_ERROR_NONE;
600 bool CForward::AddFunction(IPluginContext *pContext, funcid_t index)
602 IPluginFunction *pFunc = pContext->GetFunctionById(index);
609 return AddFunction(pFunc);
612 bool CForward::RemoveFunction(IPluginContext *pContext, funcid_t index)
614 IPluginFunction *pFunc = pContext->GetFunctionById(index);
621 return RemoveFunction(pFunc);
624 bool CForward::RemoveFunction(IPluginFunction *func)
628 List<IPluginFunction *> *lst;
630 if (func->IsRunnable())
637 for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
647 /* Cancel a call, if any */
648 if (found || m_curparam)
656 unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin)
659 IPluginFunction *func;
660 unsigned int removed = 0;
661 IPluginContext *pContext = plugin->GetBaseContext();
662 for (iter=m_functions.begin(); iter!=m_functions.end();)
665 if (func->GetParentContext() == pContext)
667 iter = m_functions.erase(iter);
677 bool CForward::AddFunction(IPluginFunction *func)
684 if (func->IsRunnable())
686 m_functions.push_back(func);
688 m_paused.push_back(func);
694 const char *CForward::GetForwardName()
699 unsigned int CForward::GetFunctionCount()
701 return m_functions.size();
704 ExecType CForward::GetExecType()