core/systems/ForwardSys.cpp
author Borja Ferrer <faluco@alliedmods.net>
Sat Mar 17 00:55:46 2007 +0000 (2007-03-17)
changeset 641 ce1f369ba889
parent 621 5a0f5014aac1
child 653 ef60870067ff
permissions -rw-r--r--
fixed several memory leaks
fixed plugin listeners being removed before a OnPluginUnloaded Call_AskPluginLoad
removed some virtuality
all cached ptrs using the Stack system are freed now
     1 /**
     2  * ===============================================================
     3  * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     4  * ===============================================================
     5  *
     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
    10  *
    11  * Version: $Id$
    12  */
    13 
    14 #include <assert.h>
    15 #include <stdarg.h>
    16 #include <string.h>
    17 #include "ForwardSys.h"
    18 #include "PluginSys.h"
    19 #include "ShareSys.h"
    20 
    21 CForwardManager g_Forwards;
    22 
    23 /**
    24  * Gensis turns to its source, reduction occurs stepwise although the essence is all one.
    25  * End of line.  FTL system check.
    26  *
    27  * :TODO: WHAT NEEDS TO BE TESTED IN THIS BEAST
    28  * VARARG FUNCTIONS:
    29  * - Pushing no varargs
    30  */
    31 
    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!
    34 
    35 CForwardManager::~CForwardManager()
    36 {
    37 	CStack<CForward *>::iterator iter;
    38 	for (iter=m_FreeForwards.begin(); iter!=m_FreeForwards.end(); iter++)
    39 	{
    40 		delete (*iter);
    41 	}
    42 	m_FreeForwards.popall();
    43 }
    44 
    45 void CForwardManager::OnSourceModAllInitialized()
    46 {
    47 	g_PluginSys.AddPluginsListener(this);
    48 	g_ShareSys.AddInterface(NULL, this);
    49 }
    50 
    51 IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned int num_params, const ParamType *types, ...)
    52 {
    53 	CForward *fwd;
    54 	va_list ap;
    55 	va_start(ap, types);
    56 	
    57 	fwd = CForward::CreateForward(name, et, num_params, types, ap);
    58 
    59 	va_end(ap);
    60 
    61 	if (fwd)
    62 	{
    63 		g_PluginSys.AddFunctionsToForward(name, fwd);
    64 
    65 		m_managed.push_back(fwd);
    66 	}
    67 
    68 	return fwd;
    69 }
    70 
    71 IChangeableForward *CForwardManager::CreateForwardEx(const char *name, ExecType et, int num_params, const ParamType *types, ...)
    72 {
    73 	CForward *fwd;
    74 	va_list ap;
    75 	va_start(ap, types);
    76 
    77 	fwd = CForward::CreateForward(name, et, num_params, types, ap);
    78 
    79 	va_end(ap);
    80 
    81 	if (fwd)
    82 	{
    83 		m_unmanaged.push_back(fwd);
    84 	}
    85 
    86 	return fwd;
    87 }
    88 
    89 void CForwardManager::OnPluginLoaded(IPlugin *plugin)
    90 {
    91 	/* Attach any globally managed forwards */
    92 	List<CForward *>::iterator iter;
    93 	CForward *fwd;
    94 
    95 	for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
    96 	{
    97 		fwd = (*iter);
    98 		IPluginFunction *pFunc = plugin->GetBaseContext()->GetFunctionByName(fwd->GetForwardName());
    99 		if (pFunc)
   100 		{
   101 			fwd->AddFunction(pFunc);
   102 		}
   103 	}
   104 }
   105 
   106 void CForwardManager::OnPluginUnloaded(IPlugin *plugin)
   107 {
   108 	List<CForward *>::iterator iter;
   109 	CForward *fwd;
   110 
   111 	for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
   112 	{
   113 		fwd = (*iter);
   114 		fwd->RemoveFunctionsOfPlugin(plugin);
   115 	}
   116 
   117 	for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
   118 	{
   119 		fwd = (*iter);
   120 		fwd->RemoveFunctionsOfPlugin(plugin);
   121 	}
   122 }
   123 
   124 IForward *CForwardManager::FindForward(const char *name, IChangeableForward **ifchng)
   125 {
   126 	List<CForward *>::iterator iter;
   127 	CForward *fwd;
   128 
   129 	for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
   130 	{
   131 		fwd = (*iter);
   132 		if (strcmp(fwd->GetForwardName(), name) == 0)
   133 		{
   134 			if (ifchng)
   135 			{
   136 				*ifchng = NULL;
   137 			}
   138 			return fwd;
   139 		}
   140 	}
   141 
   142 	for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
   143 	{
   144 		fwd = (*iter);
   145 		if (strcmp(fwd->GetForwardName(), name) == 0)
   146 		{
   147 			if (ifchng)
   148 			{
   149 				*ifchng = fwd;
   150 			}
   151 			return fwd;
   152 		}
   153 	}
   154 
   155 	if (ifchng)
   156 	{
   157 		*ifchng = NULL;
   158 	}
   159 
   160 	return NULL;
   161 }
   162 
   163 void CForwardManager::ReleaseForward(IForward *forward)
   164 {
   165 	ForwardFree(static_cast<CForward *>(forward));
   166 }
   167 
   168 void CForwardManager::ForwardFree(CForward *fwd)
   169 {
   170 	m_FreeForwards.push(fwd);
   171 	m_managed.remove(fwd);
   172 }
   173 
   174 CForward *CForwardManager::ForwardMake()
   175 {
   176 	CForward *fwd;
   177 	if (m_FreeForwards.empty())
   178 	{
   179 		fwd = new CForward;
   180 	} else {
   181 		fwd = m_FreeForwards.front();
   182 		m_FreeForwards.pop();
   183 	}
   184 	return fwd;
   185 }
   186 
   187 void CForwardManager::OnPluginPauseChange(IPlugin *plugin, bool paused)
   188 {
   189 	/* No longer used */
   190 }
   191 
   192 /*************************************
   193  * ACTUAL FORWARD API IMPLEMENTATION *
   194  *************************************/
   195 
   196 CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int num_params, const ParamType *types, va_list ap)
   197 {
   198 	ParamType _types[SP_MAX_EXEC_PARAMS];
   199 
   200 	if (num_params > SP_MAX_EXEC_PARAMS)
   201 	{
   202 		return NULL;
   203 	}
   204 	
   205 	if (types == NULL && num_params)
   206 	{
   207 		for (unsigned int i=0; i<num_params; i++)
   208 		{
   209 			_types[i] = (ParamType)va_arg(ap, int);
   210 			if (_types[i] == Param_VarArgs && (i != num_params - 1))
   211 			{
   212 				return NULL;
   213 			}
   214 		}
   215 		types = _types;
   216 	} else {
   217 		for (unsigned int i=0; i<num_params; i++)
   218 		{
   219 			_types[i] = types[i];
   220 			if (types[i] == Param_VarArgs && (i != num_params - 1))
   221 			{
   222 				return NULL;
   223 			}
   224 		}
   225 	}
   226 
   227 	/* First parameter can never be varargs */
   228 	if (num_params && _types[0] == Param_VarArgs)
   229 	{
   230 		return NULL;
   231 	}
   232 
   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 : "");
   237 	
   238 	for (unsigned int i=0; i<num_params; i++)
   239 	{
   240 		pForward->m_types[i] = _types[i];
   241 	}
   242 
   243 	if (num_params && _types[num_params-1] == Param_VarArgs)
   244 	{
   245 		pForward->m_varargs = num_params--;
   246 	} else {
   247 		pForward->m_varargs = false;
   248 	}
   249 
   250 	pForward->m_numparams = num_params;
   251 	pForward->m_errstate = SP_ERROR_NONE;
   252 
   253 	return pForward;
   254 }
   255 
   256 int CForward::Execute(cell_t *result, IForwardFilter *filter)
   257 {
   258 	if (m_errstate)
   259 	{
   260 		int err = m_errstate;
   261 		Cancel();
   262 		return err;
   263 	}
   264 
   265 	if (filter)
   266 	{
   267 		filter->OnExecuteBegin();
   268 	}
   269 
   270 	FuncIter iter = m_functions.begin();
   271 	IPluginFunction *func;
   272 	cell_t cur_result = 0;
   273 	cell_t high_result = 0;
   274 	int err;
   275 	unsigned int failed=0, success=0;
   276 	unsigned int num_params = m_curparam;
   277 	FwdParamInfo temp_info[SP_MAX_EXEC_PARAMS];
   278 	FwdParamInfo *param;
   279 	ParamType type;
   280 
   281 	/* Save local, reset */
   282 	memcpy(temp_info, m_params, sizeof(m_params));
   283 	m_curparam = 0;
   284 
   285 	for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
   286 	{
   287 		func = (*iter);
   288 
   289 		for (unsigned int i=0; i<num_params; i++)
   290 		{
   291 			param = &temp_info[i];
   292 			if (i >= m_numparams || m_types[i] == Param_Any)
   293 			{
   294 				type = param->pushedas;
   295 			} else {
   296 				type = m_types[i];
   297 			}
   298 			if ((i >= m_numparams) || (type & SP_PARAMFLAG_BYREF))
   299 			{
   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.
   302 				 */
   303 				if (type == Param_String)
   304 				{
   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(&param->val); 
   308 				} else {
   309 					func->PushArray(param->byref.orig_addr, param->byref.cells, param->byref.flags);
   310 					assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef);
   311 				}
   312 			} else {
   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);
   316 			}
   317 		}
   318 		
   319 		/* Call the function and deal with the return value. */
   320 		if ((err=func->Execute(&cur_result)) != SP_ERROR_NONE)
   321 		{
   322 			bool handled = false;
   323 			if (filter)
   324 			{
   325 				handled = filter->OnErrorReport(this, func, err);
   326 			}
   327 			if (!handled)
   328 			{
   329 				/* :TODO: invoke global error reporting here */
   330 			}
   331 			failed++;
   332 		} else {
   333 			success++;
   334 			switch (m_ExecType)
   335 			{
   336 			case ET_Event:
   337 				{
   338 					if (cur_result > high_result)
   339 					{
   340 						high_result = cur_result;
   341 					}
   342 					break;
   343 				}
   344 			case ET_Hook:
   345 				{
   346 					if (cur_result > high_result)
   347 					{
   348 						high_result = cur_result;
   349 						if ((ResultType)high_result == Pl_Stop)
   350 						{
   351 							iter = m_functions.end();
   352 							break;
   353 						}
   354 					}
   355 					break;
   356 				}
   357 			case ET_Custom:
   358 				{
   359 					if (filter)
   360 					{
   361 						if (filter->OnFunctionReturn(this, func, &cur_result) == Pl_Stop)
   362 						{
   363 							iter = m_functions.end();
   364 						}
   365 					}
   366 					break;
   367 				}
   368 			default:
   369 				{
   370 					break;
   371 				}
   372 			}
   373 		}
   374 	}
   375 
   376 	if (success)
   377 	{
   378 		if (m_ExecType == ET_Event || m_ExecType == ET_Hook)
   379 		{
   380 			cur_result = high_result;
   381 		} else if (m_ExecType == ET_Ignore) {
   382 			cur_result = 0;
   383 		}
   384 		if (result)
   385 		{
   386 			*result = cur_result;
   387 		}
   388 	}
   389 
   390 	if (filter)
   391 	{
   392 		filter->OnExecuteEnd(&cur_result, success, failed);
   393 	}
   394 
   395 	return SP_ERROR_NONE;
   396 }
   397 
   398 int CForward::PushCell(cell_t cell)
   399 {
   400 	if (m_curparam < m_numparams)
   401 	{
   402 		if (m_types[m_curparam] == Param_Any)
   403 		{
   404 			m_params[m_curparam].pushedas = Param_Cell;
   405 		} else if (m_types[m_curparam] != Param_Cell) {
   406 			return SetError(SP_ERROR_PARAM);
   407 		}
   408 	} else {
   409 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   410 		{
   411 			return SetError(SP_ERROR_PARAMS_MAX);
   412 		}
   413 		m_params[m_curparam].pushedas = Param_Cell;
   414 	}
   415 
   416 	m_params[m_curparam++].val = cell;
   417 
   418 	return SP_ERROR_NONE;
   419 }
   420 
   421 int CForward::PushFloat(float number)
   422 {
   423 	if (m_curparam < m_numparams)
   424 	{
   425 		if (m_types[m_curparam] == Param_Any)
   426 		{
   427 			m_params[m_curparam].pushedas = Param_Float;
   428 		} else if (m_types[m_curparam] != Param_Float) {
   429 			return SetError(SP_ERROR_PARAM);
   430 		}
   431 	} else {
   432 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   433 		{
   434 			return SetError(SP_ERROR_PARAMS_MAX);
   435 		}
   436 		m_params[m_curparam].pushedas = Param_Float;
   437 	}
   438 
   439 	m_params[m_curparam++].val = *(cell_t *)&number;
   440 
   441 	return SP_ERROR_NONE;
   442 }
   443 
   444 int CForward::PushCellByRef(cell_t *cell, int flags)
   445 {
   446 	if (m_curparam < m_numparams)
   447 	{
   448 		if (m_types[m_curparam] == Param_Any)
   449 		{
   450 			m_params[m_curparam].pushedas = Param_CellByRef;
   451 		} else if (m_types[m_curparam] != Param_CellByRef) {
   452 			return SetError(SP_ERROR_PARAM);
   453 		}
   454 	} else {
   455 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   456 		{
   457 			return SetError(SP_ERROR_PARAMS_MAX);
   458 		}
   459 		m_params[m_curparam].pushedas = Param_CellByRef;
   460 	}
   461 
   462 	_Int_PushArray(cell, 1, flags);
   463 	m_curparam++;
   464 
   465 	return SP_ERROR_NONE;
   466 }
   467 
   468 int CForward::PushFloatByRef(float *num, int flags)
   469 {
   470 	if (m_curparam < m_numparams)
   471 	{
   472 		if (m_types[m_curparam] == Param_Any)
   473 		{
   474 			m_params[m_curparam].pushedas = Param_FloatByRef;
   475 		} else if (m_types[m_curparam] != Param_FloatByRef) {
   476 			return SetError(SP_ERROR_PARAM);
   477 		}
   478 	} else {
   479 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   480 		{
   481 			return SetError(SP_ERROR_PARAMS_MAX);
   482 		}
   483 		m_params[m_curparam].pushedas = Param_FloatByRef;
   484 	}
   485 
   486 	_Int_PushArray((cell_t *)num, 1, flags);
   487 	m_curparam++;
   488 
   489 	return SP_ERROR_NONE;
   490 }
   491 
   492 void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags)
   493 {
   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;
   497 }
   498 
   499 int CForward::PushArray(cell_t *inarray, unsigned int cells, int flags)
   500 {
   501 	/* We don't allow this here */
   502 	if (!inarray)
   503 	{
   504 		return SetError(SP_ERROR_PARAM);
   505 	}
   506 
   507 	if (m_curparam < m_numparams)
   508 	{
   509 		if (m_types[m_curparam] == Param_Any)
   510 		{
   511 			m_params[m_curparam].pushedas = Param_Array;
   512 		} else if (m_types[m_curparam] != Param_Array) {
   513 			return SetError(SP_ERROR_PARAM);
   514 		}
   515 	} else {
   516 		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
   517 		{
   518 			return SetError(SP_ERROR_PARAMS_MAX);
   519 		}
   520 		m_params[m_curparam].pushedas = Param_Array;
   521 	}
   522 
   523 	_Int_PushArray(inarray, cells, flags);
   524 
   525 	m_curparam++;
   526 
   527 	return SP_ERROR_NONE;
   528 }
   529 
   530 void CForward::_Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_flags)
   531 {
   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;
   536 }
   537 
   538 int CForward::PushString(const char *string)
   539 {
   540 	if (m_curparam < m_numparams)
   541 	{
   542 		if (m_types[m_curparam] == Param_Any)
   543 		{
   544 			m_params[m_curparam].pushedas = Param_String;
   545 		} else if (m_types[m_curparam] != Param_String) {
   546 			return SetError(SP_ERROR_PARAM);
   547 		}
   548 	} else {
   549 		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
   550 		{
   551 			return SetError(SP_ERROR_PARAMS_MAX);
   552 		}
   553 		m_params[m_curparam].pushedas = Param_String;
   554 	}
   555 
   556 	_Int_PushString((cell_t *)string, strlen(string)+1, SM_PARAM_STRING_COPY, 0);
   557 	m_curparam++;
   558 
   559 	return SP_ERROR_NONE;
   560 }
   561 
   562 int CForward::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
   563 {
   564 	if (m_curparam < m_numparams)
   565 	{
   566 		if (m_types[m_curparam] == Param_Any)
   567 		{
   568 			m_params[m_curparam].pushedas = Param_String;
   569 		} else if (m_types[m_curparam] != Param_String) {
   570 			return SetError(SP_ERROR_PARAM);
   571 		}
   572 	} else {
   573 		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
   574 		{
   575 			return SetError(SP_ERROR_PARAMS_MAX);
   576 		}
   577 		m_params[m_curparam].pushedas = Param_String;
   578 	}
   579 
   580 	_Int_PushString((cell_t *)buffer, length, sz_flags, cp_flags);
   581 	m_curparam++;
   582 
   583 	return SP_ERROR_NONE;
   584 }
   585 
   586 void CForward::Cancel()
   587 {
   588 	if (!m_curparam)
   589 	{
   590 		return;
   591 	}
   592 
   593 	m_curparam = 0;
   594 	m_errstate = SP_ERROR_NONE;
   595 }
   596 
   597 bool CForward::AddFunction(IPluginContext *pContext, funcid_t index)
   598 {
   599 	IPluginFunction *pFunc = pContext->GetFunctionById(index);
   600 
   601 	if (!pFunc)
   602 	{
   603 		return false;
   604 	}
   605 
   606 	return AddFunction(pFunc);
   607 }
   608 
   609 bool CForward::RemoveFunction(IPluginContext *pContext, funcid_t index)
   610 {
   611 	IPluginFunction *pFunc = pContext->GetFunctionById(index);
   612 
   613 	if (!pFunc)
   614 	{
   615 		return false;
   616 	}
   617 
   618 	return RemoveFunction(pFunc);
   619 }
   620 
   621 bool CForward::RemoveFunction(IPluginFunction *func)
   622 {
   623 	bool found = false;
   624 	FuncIter iter;
   625 	List<IPluginFunction *> *lst;
   626 
   627 	if (func->IsRunnable())
   628 	{
   629 		lst = &m_functions;
   630 	} else {
   631 		lst = &m_paused;
   632 	}
   633 
   634 	for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
   635 	{
   636 		if ((*iter) == func)
   637 		{
   638 			found = true;
   639 			lst->erase(iter);
   640 			break;
   641 		}
   642 	}
   643 
   644 	/* Cancel a call, if any */
   645 	if (found || m_curparam)
   646 	{
   647 		func->Cancel();
   648 	}
   649 
   650 	return found;
   651 }
   652 
   653 unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin)
   654 {
   655 	FuncIter iter;
   656 	IPluginFunction *func;
   657 	unsigned int removed = 0;
   658 	IPluginContext *pContext = plugin->GetBaseContext();
   659 	for (iter=m_functions.begin(); iter!=m_functions.end();)
   660 	{
   661 		func = (*iter);
   662 		if (func->GetParentContext() == pContext)
   663 		{
   664 			iter = m_functions.erase(iter);
   665 			removed++;
   666 		} else {
   667 			iter++;
   668 		}
   669 	}
   670 
   671 	return removed;
   672 }
   673 
   674 bool CForward::AddFunction(IPluginFunction *func)
   675 {
   676 	if (m_curparam)
   677 	{
   678 		return false;
   679 	}
   680 
   681 	if (func->IsRunnable())
   682 	{
   683 		m_functions.push_back(func);
   684 	} else {
   685 		m_paused.push_back(func);
   686 	}
   687 
   688 	return true;
   689 }
   690 
   691 const char *CForward::GetForwardName()
   692 {
   693 	return m_name;
   694 }
   695 
   696 unsigned int CForward::GetFunctionCount()
   697 {
   698 	return m_functions.size();
   699 }
   700 
   701 ExecType CForward::GetExecType()
   702 {
   703 	return m_ExecType;
   704 }