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