2 * ===============================================================
3 * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
4 * ===============================================================
6 * This file is not open source and may not be copied without explicit
7 * written permission of AlliedModders LLC. This file may not be redistributed
8 * in whole or significant part.
9 * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
17 #include "ForwardSys.h"
18 #include "PluginSys.h"
21 CForwardManager g_Forwards;
24 * Gensis turns to its source, reduction occurs stepwise although the essence is all one.
25 * End of line. FTL system check.
27 * :TODO: WHAT NEEDS TO BE TESTED IN THIS BEAST
29 * - Pushing no varargs
32 // :TODO: IMPORTANT!!! The result pointer arg in the execute function maybe invalid if the forward fails
33 // so later evaluation of this result may cause problems on higher levels of abstraction. DOCUMENT OR FIX ALL FORWARDS!
35 CForwardManager::~CForwardManager()
37 CStack<CForward *>::iterator iter;
38 for (iter=m_FreeForwards.begin(); iter!=m_FreeForwards.end(); iter++)
42 m_FreeForwards.popall();
45 void CForwardManager::OnSourceModAllInitialized()
47 g_PluginSys.AddPluginsListener(this);
48 g_ShareSys.AddInterface(NULL, this);
51 IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned int num_params, const ParamType *types, ...)
57 fwd = CForward::CreateForward(name, et, num_params, types, ap);
63 g_PluginSys.AddFunctionsToForward(name, fwd);
65 m_managed.push_back(fwd);
71 IChangeableForward *CForwardManager::CreateForwardEx(const char *name, ExecType et, int num_params, const ParamType *types, ...)
77 fwd = CForward::CreateForward(name, et, num_params, types, ap);
83 m_unmanaged.push_back(fwd);
89 void CForwardManager::OnPluginLoaded(IPlugin *plugin)
91 /* Attach any globally managed forwards */
92 List<CForward *>::iterator iter;
95 for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
98 IPluginFunction *pFunc = plugin->GetBaseContext()->GetFunctionByName(fwd->GetForwardName());
101 fwd->AddFunction(pFunc);
106 void CForwardManager::OnPluginUnloaded(IPlugin *plugin)
108 List<CForward *>::iterator iter;
111 for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
114 fwd->RemoveFunctionsOfPlugin(plugin);
117 for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
120 fwd->RemoveFunctionsOfPlugin(plugin);
124 IForward *CForwardManager::FindForward(const char *name, IChangeableForward **ifchng)
126 List<CForward *>::iterator iter;
129 for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
132 if (strcmp(fwd->GetForwardName(), name) == 0)
142 for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
145 if (strcmp(fwd->GetForwardName(), name) == 0)
163 void CForwardManager::ReleaseForward(IForward *forward)
165 ForwardFree(static_cast<CForward *>(forward));
168 void CForwardManager::ForwardFree(CForward *fwd)
170 m_FreeForwards.push(fwd);
171 m_managed.remove(fwd);
174 CForward *CForwardManager::ForwardMake()
177 if (m_FreeForwards.empty())
181 fwd = m_FreeForwards.front();
182 m_FreeForwards.pop();
187 void CForwardManager::OnPluginPauseChange(IPlugin *plugin, bool paused)
192 /*************************************
193 * ACTUAL FORWARD API IMPLEMENTATION *
194 *************************************/
196 CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int num_params, const ParamType *types, va_list ap)
198 ParamType _types[SP_MAX_EXEC_PARAMS];
200 if (num_params > SP_MAX_EXEC_PARAMS)
205 if (types == NULL && num_params)
207 for (unsigned int i=0; i<num_params; i++)
209 _types[i] = (ParamType)va_arg(ap, int);
210 if (_types[i] == Param_VarArgs && (i != num_params - 1))
217 for (unsigned int i=0; i<num_params; i++)
219 _types[i] = types[i];
220 if (types[i] == Param_VarArgs && (i != num_params - 1))
227 /* First parameter can never be varargs */
228 if (num_params && _types[0] == Param_VarArgs)
233 CForward *pForward = g_Forwards.ForwardMake();
234 pForward->m_curparam = 0;
235 pForward->m_ExecType = et;
236 snprintf(pForward->m_name, FORWARDS_NAME_MAX, "%s", name ? name : "");
238 for (unsigned int i=0; i<num_params; i++)
240 pForward->m_types[i] = _types[i];
243 if (num_params && _types[num_params-1] == Param_VarArgs)
245 pForward->m_varargs = num_params--;
247 pForward->m_varargs = false;
250 pForward->m_numparams = num_params;
251 pForward->m_errstate = SP_ERROR_NONE;
256 int CForward::Execute(cell_t *result, IForwardFilter *filter)
260 int err = m_errstate;
267 filter->OnExecuteBegin();
270 FuncIter iter = m_functions.begin();
271 IPluginFunction *func;
272 cell_t cur_result = 0;
273 cell_t high_result = 0;
275 unsigned int failed=0, success=0;
276 unsigned int num_params = m_curparam;
277 FwdParamInfo temp_info[SP_MAX_EXEC_PARAMS];
281 /* Save local, reset */
282 memcpy(temp_info, m_params, sizeof(m_params));
285 for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
289 for (unsigned int i=0; i<num_params; i++)
291 param = &temp_info[i];
292 if (i >= m_numparams || m_types[i] == Param_Any)
294 type = param->pushedas;
298 if ((i >= m_numparams) || (type & SP_PARAMFLAG_BYREF))
300 /* If we're byref or we're vararg, we always push everything by ref.
301 * Even if they're byval, we must push them byref.
303 if (type == Param_String)
305 func->PushStringEx((char *)param->byref.orig_addr, param->byref.cells, param->byref.sz_flags, param->byref.flags);
306 } else if (type == Param_Float || type == Param_Cell) {
307 func->PushCellByRef(¶m->val);
309 func->PushArray(param->byref.orig_addr, param->byref.cells, param->byref.flags);
310 assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef);
313 /* If we're not byref or not vararg, our job is a bit easier. */
314 assert(type == Param_Cell || type == Param_Float);
315 func->PushCell(param->val);
319 /* Call the function and deal with the return value. */
320 if ((err=func->Execute(&cur_result)) != SP_ERROR_NONE)
322 bool handled = false;
325 handled = filter->OnErrorReport(this, func, err);
329 /* :TODO: invoke global error reporting here */
338 if (cur_result > high_result)
340 high_result = cur_result;
346 if (cur_result > high_result)
348 high_result = cur_result;
349 if ((ResultType)high_result == Pl_Stop)
351 iter = m_functions.end();
361 if (filter->OnFunctionReturn(this, func, &cur_result) == Pl_Stop)
363 iter = m_functions.end();
378 if (m_ExecType == ET_Event || m_ExecType == ET_Hook)
380 cur_result = high_result;
381 } else if (m_ExecType == ET_Ignore) {
386 *result = cur_result;
392 filter->OnExecuteEnd(&cur_result, success, failed);
395 return SP_ERROR_NONE;
398 int CForward::PushCell(cell_t cell)
400 if (m_curparam < m_numparams)
402 if (m_types[m_curparam] == Param_Any)
404 m_params[m_curparam].pushedas = Param_Cell;
405 } else if (m_types[m_curparam] != Param_Cell) {
406 return SetError(SP_ERROR_PARAM);
409 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
411 return SetError(SP_ERROR_PARAMS_MAX);
413 m_params[m_curparam].pushedas = Param_Cell;
416 m_params[m_curparam++].val = cell;
418 return SP_ERROR_NONE;
421 int CForward::PushFloat(float number)
423 if (m_curparam < m_numparams)
425 if (m_types[m_curparam] == Param_Any)
427 m_params[m_curparam].pushedas = Param_Float;
428 } else if (m_types[m_curparam] != Param_Float) {
429 return SetError(SP_ERROR_PARAM);
432 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
434 return SetError(SP_ERROR_PARAMS_MAX);
436 m_params[m_curparam].pushedas = Param_Float;
439 m_params[m_curparam++].val = *(cell_t *)&number;
441 return SP_ERROR_NONE;
444 int CForward::PushCellByRef(cell_t *cell, int flags)
446 if (m_curparam < m_numparams)
448 if (m_types[m_curparam] == Param_Any)
450 m_params[m_curparam].pushedas = Param_CellByRef;
451 } else if (m_types[m_curparam] != Param_CellByRef) {
452 return SetError(SP_ERROR_PARAM);
455 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
457 return SetError(SP_ERROR_PARAMS_MAX);
459 m_params[m_curparam].pushedas = Param_CellByRef;
462 _Int_PushArray(cell, 1, flags);
465 return SP_ERROR_NONE;
468 int CForward::PushFloatByRef(float *num, int flags)
470 if (m_curparam < m_numparams)
472 if (m_types[m_curparam] == Param_Any)
474 m_params[m_curparam].pushedas = Param_FloatByRef;
475 } else if (m_types[m_curparam] != Param_FloatByRef) {
476 return SetError(SP_ERROR_PARAM);
479 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
481 return SetError(SP_ERROR_PARAMS_MAX);
483 m_params[m_curparam].pushedas = Param_FloatByRef;
486 _Int_PushArray((cell_t *)num, 1, flags);
489 return SP_ERROR_NONE;
492 void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags)
494 m_params[m_curparam].byref.cells = cells;
495 m_params[m_curparam].byref.flags = flags;
496 m_params[m_curparam].byref.orig_addr = inarray;
499 int CForward::PushArray(cell_t *inarray, unsigned int cells, int flags)
501 /* We don't allow this here */
504 return SetError(SP_ERROR_PARAM);
507 if (m_curparam < m_numparams)
509 if (m_types[m_curparam] == Param_Any)
511 m_params[m_curparam].pushedas = Param_Array;
512 } else if (m_types[m_curparam] != Param_Array) {
513 return SetError(SP_ERROR_PARAM);
516 if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
518 return SetError(SP_ERROR_PARAMS_MAX);
520 m_params[m_curparam].pushedas = Param_Array;
523 _Int_PushArray(inarray, cells, flags);
527 return SP_ERROR_NONE;
530 void CForward::_Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_flags)
532 m_params[m_curparam].byref.cells = cells; /* Notice this contains the char count not cell count */
533 m_params[m_curparam].byref.flags = cp_flags;
534 m_params[m_curparam].byref.orig_addr = inarray;
535 m_params[m_curparam].byref.sz_flags = sz_flags;
538 int CForward::PushString(const char *string)
540 if (m_curparam < m_numparams)
542 if (m_types[m_curparam] == Param_Any)
544 m_params[m_curparam].pushedas = Param_String;
545 } else if (m_types[m_curparam] != Param_String) {
546 return SetError(SP_ERROR_PARAM);
549 if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
551 return SetError(SP_ERROR_PARAMS_MAX);
553 m_params[m_curparam].pushedas = Param_String;
556 _Int_PushString((cell_t *)string, strlen(string)+1, SM_PARAM_STRING_COPY, 0);
559 return SP_ERROR_NONE;
562 int CForward::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
564 if (m_curparam < m_numparams)
566 if (m_types[m_curparam] == Param_Any)
568 m_params[m_curparam].pushedas = Param_String;
569 } else if (m_types[m_curparam] != Param_String) {
570 return SetError(SP_ERROR_PARAM);
573 if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
575 return SetError(SP_ERROR_PARAMS_MAX);
577 m_params[m_curparam].pushedas = Param_String;
580 _Int_PushString((cell_t *)buffer, length, sz_flags, cp_flags);
583 return SP_ERROR_NONE;
586 void CForward::Cancel()
594 m_errstate = SP_ERROR_NONE;
597 bool CForward::AddFunction(IPluginContext *pContext, funcid_t index)
599 IPluginFunction *pFunc = pContext->GetFunctionById(index);
606 return AddFunction(pFunc);
609 bool CForward::RemoveFunction(IPluginContext *pContext, funcid_t index)
611 IPluginFunction *pFunc = pContext->GetFunctionById(index);
618 return RemoveFunction(pFunc);
621 bool CForward::RemoveFunction(IPluginFunction *func)
625 List<IPluginFunction *> *lst;
627 if (func->IsRunnable())
634 for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
644 /* Cancel a call, if any */
645 if (found || m_curparam)
653 unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin)
656 IPluginFunction *func;
657 unsigned int removed = 0;
658 IPluginContext *pContext = plugin->GetBaseContext();
659 for (iter=m_functions.begin(); iter!=m_functions.end();)
662 if (func->GetParentContext() == pContext)
664 iter = m_functions.erase(iter);
674 bool CForward::AddFunction(IPluginFunction *func)
681 if (func->IsRunnable())
683 m_functions.push_back(func);
685 m_paused.push_back(func);
691 const char *CForward::GetForwardName()
696 unsigned int CForward::GetFunctionCount()
698 return m_functions.size();
701 ExecType CForward::GetExecType()