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