core/systems/ForwardSys.cpp
author David Anderson <dvander@alliedmods.net>
Thu Feb 22 02:20:15 2007 +0000 (2007-02-22)
changeset 527 6613e685b45b
parent 526 bcb82491f9df
child 529 830259af8435
permissions -rw-r--r--
re-added this back, it was a good idea after all
     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, 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, 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, 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 			if (types[i] == Param_VarArgs && (i != num_params - 1))
   213 			{
   214 				return NULL;
   215 			}
   216 		}
   217 	}
   218 
   219 	/* First parameter can never be varargs */
   220 	if (types[0] == Param_VarArgs)
   221 	{
   222 		return NULL;
   223 	}
   224 
   225 	CForward *pForward = g_Forwards.ForwardMake();
   226 	pForward->m_curparam = 0;
   227 	pForward->m_ExecType = et;
   228 	snprintf(pForward->m_name, FORWARDS_NAME_MAX, "%s", name ? name : "");
   229 	
   230 	for (unsigned int i=0; i<num_params; i++)
   231 	{
   232 		pForward->m_types[i] = types[i];
   233 	}
   234 
   235 	if (num_params && types[num_params-1] == Param_VarArgs)
   236 	{
   237 		pForward->m_varargs = num_params--;
   238 	} else {
   239 		pForward->m_varargs = false;
   240 	}
   241 
   242 	pForward->m_numparams = num_params;
   243 	pForward->m_errstate = SP_ERROR_NONE;
   244 
   245 	return pForward;
   246 }
   247 
   248 int CForward::Execute(cell_t *result, IForwardFilter *filter)
   249 {
   250 	if (m_errstate)
   251 	{
   252 		int err = m_errstate;
   253 		Cancel();
   254 		return err;
   255 	}
   256 
   257 	if (filter)
   258 	{
   259 		filter->OnExecuteBegin();
   260 	}
   261 
   262 	FuncIter iter = m_functions.begin();
   263 	IPluginFunction *func;
   264 	cell_t cur_result = 0;
   265 	cell_t high_result = 0;
   266 	int err;
   267 	unsigned int failed=0, success=0;
   268 	unsigned int num_params = m_curparam;
   269 	FwdParamInfo temp_info[SP_MAX_EXEC_PARAMS];
   270 	FwdParamInfo *param;
   271 	ParamType type;
   272 
   273 	/* Save local, reset */
   274 	memcpy(temp_info, m_params, sizeof(m_params));
   275 	m_curparam = 0;
   276 
   277 	for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
   278 	{
   279 		func = (*iter);
   280 
   281 		for (unsigned int i=0; i<num_params; i++)
   282 		{
   283 			param = &temp_info[i];
   284 			if (i >= m_numparams || m_types[i] == Param_Any)
   285 			{
   286 				type = param->pushedas;
   287 			} else {
   288 				type = m_types[i];
   289 			}
   290 			if ((i >= m_numparams) || (type & SP_PARAMFLAG_BYREF))
   291 			{
   292 				/* If we're byref or we're vararg, we always push everything by ref.
   293 				 * Even if they're byval, we must push them byref.
   294 				 */
   295 				if (type == Param_String)
   296 				{
   297 					func->PushStringEx((char *)param->byref.orig_addr, param->byref.cells, param->byref.sz_flags, param->byref.flags);
   298 				} else if (type == Param_Float || type == Param_Cell) {
   299 					func->PushCellByRef(&param->val, 0); 
   300 				} else {
   301 					func->PushArray(param->byref.orig_addr, param->byref.cells, NULL, param->byref.flags);
   302 					assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef);
   303 				}
   304 			} else {
   305 				/* If we're not byref or not vararg, our job is a bit easier. */
   306 				assert(type == Param_Cell || type == Param_Float);
   307 				func->PushCell(param->val);
   308 			}
   309 		}
   310 		
   311 		/* Call the function and deal with the return value. */
   312 		if ((err=func->Execute(&cur_result)) != SP_ERROR_NONE)
   313 		{
   314 			bool handled = false;
   315 			if (filter)
   316 			{
   317 				handled = filter->OnErrorReport(this, func, err);
   318 			}
   319 			if (!handled)
   320 			{
   321 				/* :TODO: invoke global error reporting here */
   322 			}
   323 			failed++;
   324 		} else {
   325 			success++;
   326 			switch (m_ExecType)
   327 			{
   328 			case ET_Event:
   329 				{
   330 					if (cur_result > high_result)
   331 					{
   332 						high_result = cur_result;
   333 					}
   334 					break;
   335 				}
   336 			case ET_Hook:
   337 				{
   338 					if (cur_result > high_result)
   339 					{
   340 						high_result = cur_result;
   341 						if ((ResultType)high_result == Pl_Stop)
   342 						{
   343 							iter = m_functions.end();
   344 							break;
   345 						}
   346 					}
   347 					break;
   348 				}
   349 			case ET_Custom:
   350 				{
   351 					if (filter)
   352 					{
   353 						if (filter->OnFunctionReturn(this, func, &cur_result) == Pl_Stop)
   354 						{
   355 							iter = m_functions.end();
   356 						}
   357 					}
   358 					break;
   359 				}
   360 			default:
   361 				{
   362 					break;
   363 				}
   364 			}
   365 		}
   366 	}
   367 
   368 	if (success)
   369 	{
   370 		if (m_ExecType == ET_Event || m_ExecType == ET_Hook)
   371 		{
   372 			cur_result = high_result;
   373 		} else if (m_ExecType == ET_Ignore) {
   374 			cur_result = 0;
   375 		}
   376 		if (result)
   377 		{
   378 			*result = cur_result;
   379 		}
   380 	}
   381 
   382 	if (filter)
   383 	{
   384 		filter->OnExecuteEnd(&cur_result, success, failed);
   385 	}
   386 
   387 	return SP_ERROR_NONE;
   388 }
   389 
   390 int CForward::PushCell(cell_t cell)
   391 {
   392 	if (m_curparam < m_numparams)
   393 	{
   394 		if (m_types[m_curparam] == Param_Any)
   395 		{
   396 			m_params[m_curparam].pushedas = Param_Cell;
   397 		} else if (m_types[m_curparam] != Param_Cell) {
   398 			return SetError(SP_ERROR_PARAM);
   399 		}
   400 	} else {
   401 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   402 		{
   403 			return SetError(SP_ERROR_PARAMS_MAX);
   404 		}
   405 		m_params[m_curparam].pushedas = Param_Cell;
   406 	}
   407 
   408 	m_params[m_curparam++].val = cell;
   409 
   410 	return SP_ERROR_NONE;
   411 }
   412 
   413 int CForward::PushFloat(float number)
   414 {
   415 	if (m_curparam < m_numparams)
   416 	{
   417 		if (m_types[m_curparam] == Param_Any)
   418 		{
   419 			m_params[m_curparam].pushedas = Param_Float;
   420 		} else if (m_types[m_curparam] != Param_Float) {
   421 			return SetError(SP_ERROR_PARAM);
   422 		}
   423 	} else {
   424 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   425 		{
   426 			return SetError(SP_ERROR_PARAMS_MAX);
   427 		}
   428 		m_params[m_curparam].pushedas = Param_Float;
   429 	}
   430 
   431 	m_params[m_curparam++].val = *(cell_t *)&number;
   432 
   433 	return SP_ERROR_NONE;
   434 }
   435 
   436 int CForward::PushCellByRef(cell_t *cell, int flags)
   437 {
   438 	if (m_curparam < m_numparams)
   439 	{
   440 		if (m_types[m_curparam] == Param_Any)
   441 		{
   442 			m_params[m_curparam].pushedas = Param_CellByRef;
   443 		} else if (m_types[m_curparam] != Param_CellByRef) {
   444 			return SetError(SP_ERROR_PARAM);
   445 		}
   446 	} else {
   447 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   448 		{
   449 			return SetError(SP_ERROR_PARAMS_MAX);
   450 		}
   451 		m_params[m_curparam].pushedas = Param_CellByRef;
   452 	}
   453 
   454 	_Int_PushArray(cell, 1, flags);
   455 	m_curparam++;
   456 
   457 	return SP_ERROR_NONE;
   458 }
   459 
   460 int CForward::PushFloatByRef(float *num, int flags)
   461 {
   462 	if (m_curparam < m_numparams)
   463 	{
   464 		if (m_types[m_curparam] == Param_Any)
   465 		{
   466 			m_params[m_curparam].pushedas = Param_FloatByRef;
   467 		} else if (m_types[m_curparam] != Param_FloatByRef) {
   468 			return SetError(SP_ERROR_PARAM);
   469 		}
   470 	} else {
   471 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   472 		{
   473 			return SetError(SP_ERROR_PARAMS_MAX);
   474 		}
   475 		m_params[m_curparam].pushedas = Param_FloatByRef;
   476 	}
   477 
   478 	_Int_PushArray((cell_t *)num, 1, flags);
   479 	m_curparam++;
   480 
   481 	return SP_ERROR_NONE;
   482 }
   483 
   484 void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags)
   485 {
   486 	m_params[m_curparam].byref.cells = cells;
   487 	m_params[m_curparam].byref.flags = flags;
   488 	m_params[m_curparam].byref.orig_addr = inarray;
   489 }
   490 
   491 int CForward::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int flags)
   492 {
   493 	/* We don't allow this here */
   494 	if (!inarray)
   495 	{
   496 		return SetError(SP_ERROR_PARAM);
   497 	}
   498 
   499 	if (m_curparam < m_numparams)
   500 	{
   501 		if (m_types[m_curparam] == Param_Any)
   502 		{
   503 			m_params[m_curparam].pushedas = Param_Array;
   504 		} else if (m_types[m_curparam] != Param_Array) {
   505 			return SetError(SP_ERROR_PARAM);
   506 		}
   507 	} else {
   508 		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
   509 		{
   510 			return SetError(SP_ERROR_PARAMS_MAX);
   511 		}
   512 		m_params[m_curparam].pushedas = Param_Array;
   513 	}
   514 
   515 	if (phys_addr)
   516 	{
   517 		*phys_addr = NULL;
   518 	}
   519 
   520 	_Int_PushArray(inarray, cells, flags);
   521 
   522 	m_curparam++;
   523 
   524 	return SP_ERROR_NONE;
   525 }
   526 
   527 void CForward::_Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_flags)
   528 {
   529 	m_params[m_curparam].byref.cells = cells;	/* Notice this contains the char count not cell count */
   530 	m_params[m_curparam].byref.flags = cp_flags;
   531 	m_params[m_curparam].byref.orig_addr = inarray;
   532 	m_params[m_curparam].byref.sz_flags = sz_flags;
   533 }
   534 
   535 int CForward::PushString(const char *string)
   536 {
   537 	if (m_curparam < m_numparams)
   538 	{
   539 		if (m_types[m_curparam] == Param_Any)
   540 		{
   541 			m_params[m_curparam].pushedas = Param_String;
   542 		} else if (m_types[m_curparam] != Param_String) {
   543 			return SetError(SP_ERROR_PARAM);
   544 		}
   545 	} else {
   546 		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
   547 		{
   548 			return SetError(SP_ERROR_PARAMS_MAX);
   549 		}
   550 		m_params[m_curparam].pushedas = Param_String;
   551 	}
   552 
   553 	_Int_PushString((cell_t *)string, strlen(string)+1, SM_PARAM_STRING_COPY, 0);
   554 	m_curparam++;
   555 
   556 	return SP_ERROR_NONE;
   557 }
   558 
   559 int CForward::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
   560 {
   561 	if (m_curparam < m_numparams)
   562 	{
   563 		if (m_types[m_curparam] == Param_Any)
   564 		{
   565 			m_params[m_curparam].pushedas = Param_String;
   566 		} else if (m_types[m_curparam] != Param_String) {
   567 			return SetError(SP_ERROR_PARAM);
   568 		}
   569 	} else {
   570 		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
   571 		{
   572 			return SetError(SP_ERROR_PARAMS_MAX);
   573 		}
   574 		m_params[m_curparam].pushedas = Param_String;
   575 	}
   576 
   577 	_Int_PushString((cell_t *)buffer, length, sz_flags, cp_flags);
   578 	m_curparam++;
   579 
   580 	return SP_ERROR_NONE;
   581 }
   582 
   583 void CForward::Cancel()
   584 {
   585 	if (!m_curparam)
   586 	{
   587 		return;
   588 	}
   589 
   590 	m_curparam = 0;
   591 	m_errstate = SP_ERROR_NONE;
   592 }
   593 
   594 bool CForward::AddFunction(IPluginContext *pContext, funcid_t index)
   595 {
   596 	IPluginFunction *pFunc = pContext->GetFunctionById(index);
   597 
   598 	if (!pFunc)
   599 	{
   600 		return false;
   601 	}
   602 
   603 	return AddFunction(pFunc);
   604 }
   605 
   606 bool CForward::RemoveFunction(IPluginFunction *func)
   607 {
   608 	bool found = false;
   609 	FuncIter iter;
   610 	List<IPluginFunction *> *lst;
   611 
   612 	if (func->IsRunnable())
   613 	{
   614 		lst = &m_functions;
   615 	} else {
   616 		lst = &m_paused;
   617 	}
   618 
   619 	for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
   620 	{
   621 		if ((*iter) == func)
   622 		{
   623 			found = true;
   624 			lst->erase(iter);
   625 			break;
   626 		}
   627 	}
   628 
   629 	/* Cancel a call, if any */
   630 	if (found || m_curparam)
   631 	{
   632 		func->Cancel();
   633 	}
   634 
   635 	return found;
   636 }
   637 
   638 unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin)
   639 {
   640 	FuncIter iter;
   641 	IPluginFunction *func;
   642 	unsigned int removed = 0;
   643 	IPluginContext *pContext = plugin->GetBaseContext();
   644 	for (iter=m_functions.begin(); iter!=m_functions.end();)
   645 	{
   646 		func = (*iter);
   647 		if (func->GetParentContext() == pContext)
   648 		{
   649 			iter = m_functions.erase(iter);
   650 			removed++;
   651 		} else {
   652 			iter++;
   653 		}
   654 	}
   655 
   656 	return removed;
   657 }
   658 
   659 bool CForward::AddFunction(IPluginFunction *func)
   660 {
   661 	if (m_curparam)
   662 	{
   663 		return false;
   664 	}
   665 
   666 	if (func->IsRunnable())
   667 	{
   668 		m_functions.push_back(func);
   669 	} else {
   670 		m_paused.push_back(func);
   671 	}
   672 
   673 	return true;
   674 }
   675 
   676 const char *CForward::GetForwardName() const
   677 {
   678 	return m_name;
   679 }
   680 
   681 unsigned int CForward::GetFunctionCount() const
   682 {
   683 	return m_functions.size();
   684 }
   685 
   686 ExecType CForward::GetExecType() const
   687 {
   688 	return m_ExecType;
   689 }