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 void CForwardManager::OnSourceModAllInitialized()
37 g_PluginSys.AddPluginsListener(this);
38 g_ShareSys.AddInterface(NULL, this);
41 void CForwardManager::OnSourceModShutdown()
43 g_PluginSys.RemovePluginsListener(this);
46 IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned int num_params, ParamType *types, ...)
52 fwd = CForward::CreateForward(name, et, num_params, types, ap);
58 m_managed.push_back(fwd);
64 IChangeableForward *CForwardManager::CreateForwardEx(const char *name, ExecType et, int num_params, ParamType *types, ...)
70 fwd = CForward::CreateForward(name, et, num_params, types, ap);
76 m_unmanaged.push_back(fwd);
82 void CForwardManager::OnPluginLoaded(IPlugin *plugin)
84 /* Attach any globally managed forwards */
85 List<CForward *>::iterator iter;
88 for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
91 IPluginFunction *pFunc = plugin->GetBaseContext()->GetFunctionByName(fwd->GetForwardName());
94 fwd->AddFunction(pFunc);
99 void CForwardManager::OnPluginUnloaded(IPlugin *plugin)
101 List<CForward *>::iterator iter;
104 for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
107 fwd->RemoveFunctionsOfPlugin(plugin);
110 for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
113 fwd->RemoveFunctionsOfPlugin(plugin);
117 IForward *CForwardManager::FindForward(const char *name, IChangeableForward **ifchng)
119 List<CForward *>::iterator iter;
122 for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
125 if (strcmp(fwd->GetForwardName(), name) == 0)
135 for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
138 if (strcmp(fwd->GetForwardName(), name) == 0)
156 void CForwardManager::ReleaseForward(IForward *forward)
158 ForwardFree(static_cast<CForward *>(forward));
161 void CForwardManager::ForwardFree(CForward *fwd)
163 m_FreeForwards.push(fwd);
164 m_managed.remove(fwd);
167 CForward *CForwardManager::ForwardMake()
170 if (m_FreeForwards.empty())
174 fwd = m_FreeForwards.front();
175 m_FreeForwards.pop();
180 void CForwardManager::OnPluginPauseChange(IPlugin *plugin, bool paused)
182 List<CForward *>::iterator iter;
187 for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
190 fwd->PushPausedFunctions(plugin);
192 for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
195 fwd->PushPausedFunctions(plugin);
198 for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
201 fwd->PopPausedFunctions(plugin);
203 for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
206 fwd->PopPausedFunctions(plugin);
211 /*************************************
212 * ACTUAL FORWARD API IMPLEMENTATION *
213 *************************************/
215 CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int num_params, ParamType *types, va_list ap)
217 ParamType _types[SP_MAX_EXEC_PARAMS];
219 if (num_params > SP_MAX_EXEC_PARAMS)
224 if (types == NULL && num_params)
226 for (unsigned int i=0; i<num_params; i++)
228 _types[i] = (ParamType)va_arg(ap, int);
229 if (_types[i] == Param_VarArgs && (i != num_params - 1))
236 for (unsigned int i=0; i<num_params; i++)
238 if (types[i] == Param_VarArgs && (i != num_params - 1))
245 /* First parameter can never be varargs */
246 if (types[0] == Param_VarArgs)
251 CForward *pForward = g_Forwards.ForwardMake();
252 pForward->m_curparam = 0;
253 pForward->m_ExecType = et;
254 snprintf(pForward->m_name, FORWARDS_NAME_MAX, "%s", name ? name : "");
256 for (unsigned int i=0; i<num_params; i++)
258 pForward->m_types[i] = types[i];
261 if (num_params && types[num_params-1] == Param_VarArgs)
263 pForward->m_varargs = num_params--;
265 pForward->m_varargs = false;
268 pForward->m_numparams = num_params;
269 pForward->m_errstate = SP_ERROR_NONE;
274 int CForward::Execute(cell_t *result, IForwardFilter *filter)
278 int err = m_errstate;
285 filter->OnExecuteBegin();
288 FuncIter iter = m_functions.begin();
289 IPluginFunction *func;
290 cell_t cur_result = 0;
291 cell_t high_result = 0;
293 unsigned int failed=0, success=0;
294 unsigned int num_params = m_curparam;
295 FwdParamInfo temp_info[SP_MAX_EXEC_PARAMS];
299 /* Save local, reset */
300 memcpy(temp_info, m_params, sizeof(m_params));
303 for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
307 for (unsigned int i=0; i<num_params; i++)
309 param = &temp_info[i];
310 if (i >= m_numparams || m_types[i] == Param_Any)
312 type = param->pushedas;
316 if ((i >= m_numparams) || (type & SP_PARAMFLAG_BYREF))
318 /* If we're byref or we're vararg, we always push everything by ref.
319 * Even if they're byval, we must push them byref.
321 if (type == Param_String)
323 func->PushStringEx((char *)param->byref.orig_addr, param->byref.cells, param->byref.sz_flags, param->byref.flags);
324 } else if (type == Param_Float || type == Param_Cell) {
325 func->PushCellByRef(¶m->val, 0);
327 func->PushArray(param->byref.orig_addr, param->byref.cells, NULL, param->byref.flags);
328 assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef);
331 /* If we're not byref or not vararg, our job is a bit easier. */
332 assert(type == Param_Cell || type == Param_Float);
333 func->PushCell(param->val);
337 /* Call the function and deal with the return value. */
338 if ((err=func->Execute(&cur_result)) != SP_ERROR_NONE)
340 bool handled = false;
343 handled = filter->OnErrorReport(this, func, err);
347 /* :TODO: invoke global error reporting here */
356 if (cur_result > high_result)
358 high_result = cur_result;
364 if (cur_result > high_result)
366 high_result = cur_result;
367 if ((ResultType)high_result == Pl_Stop)
369 iter = m_functions.end();
379 if (filter->OnFunctionReturn(this, func, &cur_result) == Pl_Stop)
381 iter = m_functions.end();
396 if (m_ExecType == ET_Event || m_ExecType == ET_Hook)
398 cur_result = high_result;
399 } else if (m_ExecType == ET_Ignore) {
404 *result = cur_result;
410 filter->OnExecuteEnd(&cur_result, success, failed);
413 return SP_ERROR_NONE;
416 int CForward::PushCell(cell_t cell)
418 if (m_curparam < m_numparams)
420 if (m_types[m_curparam] == Param_Any)
422 m_params[m_curparam].pushedas = Param_Cell;
423 } else if (m_types[m_curparam] != Param_Cell) {
424 return SetError(SP_ERROR_PARAM);
427 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
429 return SetError(SP_ERROR_PARAMS_MAX);
431 m_params[m_curparam].pushedas = Param_Cell;
434 m_params[m_curparam++].val = cell;
436 return SP_ERROR_NONE;
439 int CForward::PushFloat(float number)
441 if (m_curparam < m_numparams)
443 if (m_types[m_curparam] == Param_Any)
445 m_params[m_curparam].pushedas = Param_Float;
446 } else if (m_types[m_curparam] != Param_Float) {
447 return SetError(SP_ERROR_PARAM);
450 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
452 return SetError(SP_ERROR_PARAMS_MAX);
454 m_params[m_curparam].pushedas = Param_Float;
457 m_params[m_curparam++].val = *(cell_t *)&number;
459 return SP_ERROR_NONE;
462 int CForward::PushCellByRef(cell_t *cell, int flags)
464 if (m_curparam < m_numparams)
466 if (m_types[m_curparam] == Param_Any)
468 m_params[m_curparam].pushedas = Param_CellByRef;
469 } else if (m_types[m_curparam] != Param_CellByRef) {
470 return SetError(SP_ERROR_PARAM);
473 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
475 return SetError(SP_ERROR_PARAMS_MAX);
477 m_params[m_curparam].pushedas = Param_CellByRef;
480 _Int_PushArray(cell, 1, flags);
483 return SP_ERROR_NONE;
486 int CForward::PushFloatByRef(float *num, int flags)
488 if (m_curparam < m_numparams)
490 if (m_types[m_curparam] == Param_Any)
492 m_params[m_curparam].pushedas = Param_FloatByRef;
493 } else if (m_types[m_curparam] != Param_FloatByRef) {
494 return SetError(SP_ERROR_PARAM);
497 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
499 return SetError(SP_ERROR_PARAMS_MAX);
501 m_params[m_curparam].pushedas = Param_FloatByRef;
504 _Int_PushArray((cell_t *)num, 1, flags);
507 return SP_ERROR_NONE;
510 void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags)
512 m_params[m_curparam].byref.cells = cells;
513 m_params[m_curparam].byref.flags = flags;
514 m_params[m_curparam].byref.orig_addr = inarray;
517 int CForward::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int flags)
519 /* We don't allow this here */
522 return SetError(SP_ERROR_PARAM);
525 if (m_curparam < m_numparams)
527 if (m_types[m_curparam] == Param_Any)
529 m_params[m_curparam].pushedas = Param_Array;
530 } else if (m_types[m_curparam] != Param_Array) {
531 return SetError(SP_ERROR_PARAM);
534 if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
536 return SetError(SP_ERROR_PARAMS_MAX);
538 m_params[m_curparam].pushedas = Param_Array;
546 _Int_PushArray(inarray, cells, flags);
550 return SP_ERROR_NONE;
553 void CForward::_Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_flags)
555 m_params[m_curparam].byref.cells = cells; /* Notice this contains the char count not cell count */
556 m_params[m_curparam].byref.flags = cp_flags;
557 m_params[m_curparam].byref.orig_addr = inarray;
558 m_params[m_curparam].byref.sz_flags = sz_flags;
561 int CForward::PushString(const char *string)
563 if (m_curparam < m_numparams)
565 if (m_types[m_curparam] == Param_Any)
567 m_params[m_curparam].pushedas = Param_String;
568 } else if (m_types[m_curparam] != Param_String) {
569 return SetError(SP_ERROR_PARAM);
572 if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
574 return SetError(SP_ERROR_PARAMS_MAX);
576 m_params[m_curparam].pushedas = Param_String;
579 _Int_PushString((cell_t *)string, strlen(string)+1, SM_PARAM_STRING_COPY, 0);
582 return SP_ERROR_NONE;
585 int CForward::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
587 if (m_curparam < m_numparams)
589 if (m_types[m_curparam] == Param_Any)
591 m_params[m_curparam].pushedas = Param_String;
592 } else if (m_types[m_curparam] != Param_String) {
593 return SetError(SP_ERROR_PARAM);
596 if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
598 return SetError(SP_ERROR_PARAMS_MAX);
600 m_params[m_curparam].pushedas = Param_String;
603 _Int_PushString((cell_t *)buffer, length, sz_flags, cp_flags);
606 return SP_ERROR_NONE;
609 void CForward::Cancel()
617 m_errstate = SP_ERROR_NONE;
620 bool CForward::AddFunction(IPluginContext *pContext, funcid_t index)
622 IPluginFunction *pFunc = pContext->GetFunctionById(index);
629 return AddFunction(pFunc);
632 bool CForward::RemoveFunction(IPluginFunction *func)
636 List<IPluginFunction *> *lst;
638 if (func->GetParentContext()->IsRunnable())
645 for (iter=lst->begin(); iter!=lst->end(); iter++)
655 /* Cancel a call, if any */
656 if (found || m_curparam)
664 unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin)
667 IPluginFunction *func;
668 unsigned int removed = 0;
669 IPluginContext *pContext = plugin->GetBaseContext();
670 for (iter=m_functions.begin(); iter!=m_functions.end();)
673 if (func->GetParentContext() == pContext)
675 iter = m_functions.erase(iter);
685 bool CForward::AddFunction(IPluginFunction *func)
692 //:IDEA: eventually we will tell the plugin we're using it [?]
693 if (func->GetParentContext()->IsRunnable())
695 m_functions.push_back(func);
697 m_paused.push_back(func);
703 const char *CForward::GetForwardName() const
708 unsigned int CForward::GetFunctionCount() const
710 return m_functions.size();
713 ExecType CForward::GetExecType() const
718 void CForward::PushPausedFunctions(IPlugin *plugin)
721 IPluginFunction *func;
722 IPluginContext *pContext = plugin->GetBaseContext();
724 for (iter=m_functions.begin(); iter!=m_functions.end();)
727 if (func->GetParentContext() == pContext)
729 m_paused.push_back(func);
730 iter = m_functions.erase(iter);
737 void CForward::PopPausedFunctions(IPlugin *plugin)
740 IPluginFunction *func;
741 IPluginContext *pContext = plugin->GetBaseContext();
743 for (iter=m_paused.begin(); iter!=m_paused.end();)
746 if (func->GetParentContext() == pContext)
748 m_functions.push_back(func);
749 iter = m_paused.erase(iter);