3 * =============================================================================
5 * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
6 * =============================================================================
8 * This program is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, version 3.0, as published by the
10 * Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
20 * As a special exception, AlliedModders LLC gives you permission to link the
21 * code of this program (as well as its derivative works) to "Half-Life 2," the
22 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
23 * by the Valve Corporation. You must obey the GNU General Public License in
24 * all respects for all other code used. Additionally, AlliedModders LLC grants
25 * this exception to all derivative works. AlliedModders LLC defines further
26 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
27 * or <http://www.sourcemod.net/license.php>.
35 #include "ForwardSys.h"
36 #include "PluginSys.h"
38 #include "DebugReporter.h"
40 CForwardManager g_Forwards;
43 * Genesis turns to its source, reduction occurs stepwise although the essence is all one.
44 * End of line. FTL system check.
46 * :TODO: WHAT NEEDS TO BE TESTED IN THIS BEAST
48 * - Pushing no varargs
51 // :TODO: IMPORTANT!!! The result pointer arg in the execute function maybe invalid if the forward fails
52 // so later evaluation of this result may cause problems on higher levels of abstraction. DOCUMENT OR FIX ALL FORWARDS!
54 CForwardManager::~CForwardManager()
56 CStack<CForward *>::iterator iter;
57 for (iter=m_FreeForwards.begin(); iter!=m_FreeForwards.end(); iter++)
61 m_FreeForwards.popall();
64 void CForwardManager::OnSourceModAllInitialized()
66 g_PluginSys.AddPluginsListener(this);
67 g_ShareSys.AddInterface(NULL, this);
70 IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned int num_params, const ParamType *types, ...)
76 fwd = CForward::CreateForward(name, et, num_params, types, ap);
82 g_PluginSys.AddFunctionsToForward(name, fwd);
84 m_managed.push_back(fwd);
90 IChangeableForward *CForwardManager::CreateForwardEx(const char *name, ExecType et, int num_params, const ParamType *types, ...)
96 fwd = CForward::CreateForward(name, et, num_params, types, ap);
102 m_unmanaged.push_back(fwd);
108 void CForwardManager::OnPluginLoaded(IPlugin *plugin)
110 /* Attach any globally managed forwards */
111 List<CForward *>::iterator iter;
114 for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
117 IPluginFunction *pFunc = plugin->GetBaseContext()->GetFunctionByName(fwd->GetForwardName());
120 fwd->AddFunction(pFunc);
125 void CForwardManager::OnPluginUnloaded(IPlugin *plugin)
127 List<CForward *>::iterator iter;
130 for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
133 fwd->RemoveFunctionsOfPlugin(plugin);
136 for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
139 fwd->RemoveFunctionsOfPlugin(plugin);
143 IForward *CForwardManager::FindForward(const char *name, IChangeableForward **ifchng)
145 List<CForward *>::iterator iter;
148 for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
151 if (strcmp(fwd->GetForwardName(), name) == 0)
161 for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
164 if (strcmp(fwd->GetForwardName(), name) == 0)
182 void CForwardManager::ReleaseForward(IForward *forward)
184 ForwardFree(static_cast<CForward *>(forward));
187 void CForwardManager::ForwardFree(CForward *fwd)
189 m_FreeForwards.push(fwd);
190 m_managed.remove(fwd);
193 CForward *CForwardManager::ForwardMake()
196 if (m_FreeForwards.empty())
200 fwd = m_FreeForwards.front();
201 m_FreeForwards.pop();
206 void CForwardManager::OnPluginPauseChange(IPlugin *plugin, bool paused)
211 /*************************************
212 * ACTUAL FORWARD API IMPLEMENTATION *
213 *************************************/
215 CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int num_params, const 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 _types[i] = types[i];
239 if (types[i] == Param_VarArgs && (i != num_params - 1))
246 /* First parameter can never be varargs */
247 if (num_params && _types[0] == Param_VarArgs)
252 CForward *pForward = g_Forwards.ForwardMake();
253 pForward->m_curparam = 0;
254 pForward->m_ExecType = et;
255 snprintf(pForward->m_name, FORWARDS_NAME_MAX, "%s", name ? name : "");
257 for (unsigned int i=0; i<num_params; i++)
259 pForward->m_types[i] = _types[i];
262 if (num_params && _types[num_params-1] == Param_VarArgs)
264 pForward->m_varargs = num_params--;
266 pForward->m_varargs = false;
269 pForward->m_numparams = num_params;
270 pForward->m_errstate = SP_ERROR_NONE;
272 pForward->m_functions.clear();
277 int CForward::Execute(cell_t *result, IForwardFilter *filter)
281 int err = m_errstate;
288 filter->OnExecuteBegin();
291 FuncIter iter = m_functions.begin();
292 IPluginFunction *func;
293 cell_t cur_result = 0;
294 cell_t high_result = 0;
296 unsigned int failed=0, success=0;
297 unsigned int num_params = m_curparam;
298 FwdParamInfo temp_info[SP_MAX_EXEC_PARAMS];
302 /* Save local, reset */
303 memcpy(temp_info, m_params, sizeof(m_params));
306 for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
310 for (unsigned int i=0; i<num_params; i++)
312 int err = SP_ERROR_PARAM;
313 param = &temp_info[i];
314 if (i >= m_numparams || m_types[i] == Param_Any)
316 type = param->pushedas;
320 if ((i >= m_numparams) || (type & SP_PARAMFLAG_BYREF))
322 /* If we're byref or we're vararg, we always push everything by ref.
323 * Even if they're byval, we must push them byref.
325 if (type == Param_String)
327 err = func->PushStringEx((char *)param->byref.orig_addr, param->byref.cells, param->byref.sz_flags, param->byref.flags);
328 } else if (type == Param_Float || type == Param_Cell) {
329 err = func->PushCellByRef(¶m->val);
331 err = func->PushArray(param->byref.orig_addr, param->byref.cells, param->byref.flags);
332 assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef);
335 /* If we're not byref or not vararg, our job is a bit easier. */
336 assert(type == Param_Cell || type == Param_Float);
337 err = func->PushCell(param->val);
339 if (err != SP_ERROR_NONE)
341 if (!filter || !filter->OnErrorReport(this, func, err))
343 g_DbgReporter.GenerateError(func->GetParentContext(),
344 func->GetFunctionID(),
346 "Failed to push parameter while executing forward");
352 /* Call the function and deal with the return value. */
353 if ((err=func->Execute(&cur_result)) != SP_ERROR_NONE)
357 filter->OnErrorReport(this, func, err);
366 if (cur_result > high_result)
368 high_result = cur_result;
374 if (cur_result > high_result)
376 high_result = cur_result;
377 if ((ResultType)high_result == Pl_Stop)
388 if (filter->OnFunctionReturn(this, func, &cur_result) == Pl_Stop)
406 if (m_ExecType == ET_Event || m_ExecType == ET_Hook)
408 cur_result = high_result;
409 } else if (m_ExecType == ET_Ignore) {
414 *result = cur_result;
420 filter->OnExecuteEnd(&cur_result, success, failed);
423 return SP_ERROR_NONE;
426 int CForward::PushCell(cell_t cell)
428 if (m_curparam < m_numparams)
430 if (m_types[m_curparam] == Param_Any)
432 m_params[m_curparam].pushedas = Param_Cell;
433 } else if (m_types[m_curparam] != Param_Cell) {
434 return SetError(SP_ERROR_PARAM);
437 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
439 return SetError(SP_ERROR_PARAMS_MAX);
441 m_params[m_curparam].pushedas = Param_Cell;
444 m_params[m_curparam++].val = cell;
446 return SP_ERROR_NONE;
449 int CForward::PushFloat(float number)
451 if (m_curparam < m_numparams)
453 if (m_types[m_curparam] == Param_Any)
455 m_params[m_curparam].pushedas = Param_Float;
456 } else if (m_types[m_curparam] != Param_Float) {
457 return SetError(SP_ERROR_PARAM);
460 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
462 return SetError(SP_ERROR_PARAMS_MAX);
464 m_params[m_curparam].pushedas = Param_Float;
467 m_params[m_curparam++].val = *(cell_t *)&number;
469 return SP_ERROR_NONE;
472 int CForward::PushCellByRef(cell_t *cell, int flags)
474 if (m_curparam < m_numparams)
476 if (m_types[m_curparam] == Param_Any)
478 m_params[m_curparam].pushedas = Param_CellByRef;
479 } else if (m_types[m_curparam] != Param_CellByRef) {
480 return SetError(SP_ERROR_PARAM);
483 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
485 return SetError(SP_ERROR_PARAMS_MAX);
487 m_params[m_curparam].pushedas = Param_CellByRef;
490 _Int_PushArray(cell, 1, flags);
493 return SP_ERROR_NONE;
496 int CForward::PushFloatByRef(float *num, int flags)
498 if (m_curparam < m_numparams)
500 if (m_types[m_curparam] == Param_Any)
502 m_params[m_curparam].pushedas = Param_FloatByRef;
503 } else if (m_types[m_curparam] != Param_FloatByRef) {
504 return SetError(SP_ERROR_PARAM);
507 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
509 return SetError(SP_ERROR_PARAMS_MAX);
511 m_params[m_curparam].pushedas = Param_FloatByRef;
514 _Int_PushArray((cell_t *)num, 1, flags);
517 return SP_ERROR_NONE;
520 void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags)
522 m_params[m_curparam].byref.cells = cells;
523 m_params[m_curparam].byref.flags = flags;
524 m_params[m_curparam].byref.orig_addr = inarray;
527 int CForward::PushArray(cell_t *inarray, unsigned int cells, int flags)
529 /* We don't allow this here */
532 return SetError(SP_ERROR_PARAM);
535 if (m_curparam < m_numparams)
537 if (m_types[m_curparam] == Param_Any)
539 m_params[m_curparam].pushedas = Param_Array;
540 } else if (m_types[m_curparam] != Param_Array) {
541 return SetError(SP_ERROR_PARAM);
544 if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
546 return SetError(SP_ERROR_PARAMS_MAX);
548 m_params[m_curparam].pushedas = Param_Array;
551 _Int_PushArray(inarray, cells, flags);
555 return SP_ERROR_NONE;
558 void CForward::_Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_flags)
560 m_params[m_curparam].byref.cells = cells; /* Notice this contains the char count not cell count */
561 m_params[m_curparam].byref.flags = cp_flags;
562 m_params[m_curparam].byref.orig_addr = inarray;
563 m_params[m_curparam].byref.sz_flags = sz_flags;
566 int CForward::PushString(const char *string)
568 if (m_curparam < m_numparams)
570 if (m_types[m_curparam] == Param_Any)
572 m_params[m_curparam].pushedas = Param_String;
573 } else if (m_types[m_curparam] != Param_String) {
574 return SetError(SP_ERROR_PARAM);
577 if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
579 return SetError(SP_ERROR_PARAMS_MAX);
581 m_params[m_curparam].pushedas = Param_String;
584 _Int_PushString((cell_t *)string, strlen(string)+1, SM_PARAM_STRING_COPY, 0);
587 return SP_ERROR_NONE;
590 int CForward::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
592 if (m_curparam < m_numparams)
594 if (m_types[m_curparam] == Param_Any)
596 m_params[m_curparam].pushedas = Param_String;
597 } else if (m_types[m_curparam] != Param_String) {
598 return SetError(SP_ERROR_PARAM);
601 if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
603 return SetError(SP_ERROR_PARAMS_MAX);
605 m_params[m_curparam].pushedas = Param_String;
608 _Int_PushString((cell_t *)buffer, length, sz_flags, cp_flags);
611 return SP_ERROR_NONE;
614 void CForward::Cancel()
622 m_errstate = SP_ERROR_NONE;
625 bool CForward::AddFunction(IPluginContext *pContext, funcid_t index)
627 IPluginFunction *pFunc = pContext->GetFunctionById(index);
634 return AddFunction(pFunc);
637 bool CForward::RemoveFunction(IPluginContext *pContext, funcid_t index)
639 IPluginFunction *pFunc = pContext->GetFunctionById(index);
646 return RemoveFunction(pFunc);
649 bool CForward::RemoveFunction(IPluginFunction *func)
653 List<IPluginFunction *> *lst;
655 if (func->IsRunnable())
662 for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
672 /* Cancel a call, if any */
673 if (found || m_curparam)
681 unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin)
684 IPluginFunction *func;
685 unsigned int removed = 0;
686 IPluginContext *pContext = plugin->GetBaseContext();
687 for (iter=m_functions.begin(); iter!=m_functions.end();)
690 if (func->GetParentContext() == pContext)
692 iter = m_functions.erase(iter);
702 bool CForward::AddFunction(IPluginFunction *func)
709 if (func->IsRunnable())
711 m_functions.push_back(func);
713 m_paused.push_back(func);
719 const char *CForward::GetForwardName()
724 unsigned int CForward::GetFunctionCount()
726 return m_functions.size();
729 ExecType CForward::GetExecType()