core/systems/ForwardSys.cpp
author David Anderson <dvander@alliedmods.net>
Sat Jan 27 09:25:07 2007 +0000 (2007-01-27)
changeset 401 18fc0da83775
parent 370 d3a484f98f6d
child 430 ed37e9767ed4
permissions -rw-r--r--
fixed this using /MD in release mode
     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 /*************************************
   181  * ACTUAL FORWARD API IMPLEMENTATION *
   182  *************************************/
   183 
   184 CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int num_params, ParamType *types, va_list ap)
   185 {
   186 	ParamType _types[SP_MAX_EXEC_PARAMS];
   187 
   188 	if (num_params > SP_MAX_EXEC_PARAMS)
   189 	{
   190 		return NULL;
   191 	}
   192 	
   193 	if (types == NULL && num_params)
   194 	{
   195 		for (unsigned int i=0; i<num_params; i++)
   196 		{
   197 			_types[i] = (ParamType)va_arg(ap, int);
   198 			if (_types[i] == Param_VarArgs && (i != num_params - 1))
   199 			{
   200 				return NULL;
   201 			}
   202 		}
   203 		types = _types;
   204 	} else {
   205 		for (unsigned int i=0; i<num_params; i++)
   206 		{
   207 			if (types[i] == Param_VarArgs && (i != num_params - 1))
   208 			{
   209 				return NULL;
   210 			}
   211 		}
   212 	}
   213 
   214 	/* First parameter can never be varargs */
   215 	if (types[0] == Param_VarArgs)
   216 	{
   217 		return NULL;
   218 	}
   219 
   220 	CForward *pForward = g_Forwards.ForwardMake();
   221 	pForward->m_curparam = 0;
   222 	pForward->m_ExecType = et;
   223 	snprintf(pForward->m_name, FORWARDS_NAME_MAX, "%s", name ? name : "");
   224 	
   225 	for (unsigned int i=0; i<num_params; i++)
   226 	{
   227 		pForward->m_types[i] = types[i];
   228 	}
   229 
   230 	if (num_params && types[num_params-1] == Param_VarArgs)
   231 	{
   232 		pForward->m_varargs = num_params--;
   233 	} else {
   234 		pForward->m_varargs = false;
   235 	}
   236 
   237 	pForward->m_numparams = num_params;
   238 	pForward->m_errstate = SP_ERROR_NONE;
   239 
   240 	return pForward;
   241 }
   242 
   243 int CForward::Execute(cell_t *result, IForwardFilter *filter)
   244 {
   245 	if (m_errstate)
   246 	{
   247 		int err = m_errstate;
   248 		Cancel();
   249 		return err;
   250 	}
   251 
   252 	if (filter)
   253 	{
   254 		filter->OnExecuteBegin();
   255 	}
   256 
   257 	FuncIter iter = m_functions.begin();
   258 	IPluginFunction *func;
   259 	cell_t cur_result = 0;
   260 	cell_t high_result = 0;
   261 	int err;
   262 	unsigned int failed=0, success=0;
   263 	unsigned int num_params = m_curparam;
   264 	FwdParamInfo temp_info[SP_MAX_EXEC_PARAMS];
   265 	FwdParamInfo *param;
   266 	ParamType type;
   267 
   268 	/* Save local, reset */
   269 	memcpy(temp_info, m_params, sizeof(m_params));
   270 	m_curparam = 0;
   271 
   272 	for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
   273 	{
   274 		func = (*iter);
   275 		/* Ugh... */
   276 		if (!func->GetParentContext()->IsRunnable())
   277 		{
   278 			continue;
   279 		}
   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 (m_ExecType == ET_Event || m_ExecType == ET_Hook)
   369 	{
   370 		cur_result = high_result;
   371 	} else if (m_ExecType == ET_Ignore) {
   372 		cur_result = 0;
   373 	}
   374 
   375 	*result = cur_result;
   376 
   377 	if (filter)
   378 	{
   379 		filter->OnExecuteEnd(&cur_result, success, failed);
   380 	}
   381 
   382 	return SP_ERROR_NONE;
   383 }
   384 
   385 int CForward::PushCell(cell_t cell)
   386 {
   387 	if (m_curparam < m_numparams)
   388 	{
   389 		if (m_types[m_curparam] == Param_Any)
   390 		{
   391 			m_params[m_curparam].pushedas = Param_Cell;
   392 		} else if (m_types[m_curparam] != Param_Cell) {
   393 			return SetError(SP_ERROR_PARAM);
   394 		}
   395 	} else {
   396 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   397 		{
   398 			return SetError(SP_ERROR_PARAMS_MAX);
   399 		}
   400 		m_params[m_curparam].pushedas = Param_Cell;
   401 	}
   402 
   403 	m_params[m_curparam++].val = cell;
   404 
   405 	return SP_ERROR_NONE;
   406 }
   407 
   408 int CForward::PushFloat(float number)
   409 {
   410 	if (m_curparam < m_numparams)
   411 	{
   412 		if (m_types[m_curparam] == Param_Any)
   413 		{
   414 			m_params[m_curparam].pushedas = Param_Float;
   415 		} else if (m_types[m_curparam] != Param_Float) {
   416 			return SetError(SP_ERROR_PARAM);
   417 		}
   418 	} else {
   419 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   420 		{
   421 			return SetError(SP_ERROR_PARAMS_MAX);
   422 		}
   423 		m_params[m_curparam].pushedas = Param_Float;
   424 	}
   425 
   426 	m_params[m_curparam++].val = *(cell_t *)&number;
   427 
   428 	return SP_ERROR_NONE;
   429 }
   430 
   431 int CForward::PushCellByRef(cell_t *cell, int flags)
   432 {
   433 	if (m_curparam < m_numparams)
   434 	{
   435 		if (m_types[m_curparam] == Param_Any)
   436 		{
   437 			m_params[m_curparam].pushedas = Param_CellByRef;
   438 		} else if (m_types[m_curparam] != Param_CellByRef) {
   439 			return SetError(SP_ERROR_PARAM);
   440 		}
   441 	} else {
   442 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   443 		{
   444 			return SetError(SP_ERROR_PARAMS_MAX);
   445 		}
   446 		m_params[m_curparam].pushedas = Param_CellByRef;
   447 	}
   448 
   449 	_Int_PushArray(cell, 1, flags);
   450 	m_curparam++;
   451 
   452 	return SP_ERROR_NONE;
   453 }
   454 
   455 int CForward::PushFloatByRef(float *num, int flags)
   456 {
   457 	if (m_curparam < m_numparams)
   458 	{
   459 		if (m_types[m_curparam] == Param_Any)
   460 		{
   461 			m_params[m_curparam].pushedas = Param_FloatByRef;
   462 		} else if (m_types[m_curparam] != Param_FloatByRef) {
   463 			return SetError(SP_ERROR_PARAM);
   464 		}
   465 	} else {
   466 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   467 		{
   468 			return SetError(SP_ERROR_PARAMS_MAX);
   469 		}
   470 		m_params[m_curparam].pushedas = Param_FloatByRef;
   471 	}
   472 
   473 	_Int_PushArray((cell_t *)num, 1, flags);
   474 	m_curparam++;
   475 
   476 	return SP_ERROR_NONE;
   477 }
   478 
   479 void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags)
   480 {
   481 	m_params[m_curparam].byref.cells = cells;
   482 	m_params[m_curparam].byref.flags = flags;
   483 	m_params[m_curparam].byref.orig_addr = inarray;
   484 }
   485 
   486 int CForward::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int flags)
   487 {
   488 	/* We don't allow this here */
   489 	if (!inarray)
   490 	{
   491 		return SetError(SP_ERROR_PARAM);
   492 	}
   493 
   494 	if (m_curparam < m_numparams)
   495 	{
   496 		if (m_types[m_curparam] == Param_Any)
   497 		{
   498 			m_params[m_curparam].pushedas = Param_Array;
   499 		} else if (m_types[m_curparam] != Param_Array) {
   500 			return SetError(SP_ERROR_PARAM);
   501 		}
   502 	} else {
   503 		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
   504 		{
   505 			return SetError(SP_ERROR_PARAMS_MAX);
   506 		}
   507 		m_params[m_curparam].pushedas = Param_Array;
   508 	}
   509 
   510 	if (phys_addr)
   511 	{
   512 		*phys_addr = NULL;
   513 	}
   514 
   515 	_Int_PushArray(inarray, cells, flags);
   516 
   517 	m_curparam++;
   518 
   519 	return SP_ERROR_NONE;
   520 }
   521 
   522 void CForward::_Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_flags)
   523 {
   524 	m_params[m_curparam].byref.cells = cells;	/* Notice this contains the char count not cell count */
   525 	m_params[m_curparam].byref.flags = cp_flags;
   526 	m_params[m_curparam].byref.orig_addr = inarray;
   527 	m_params[m_curparam].byref.sz_flags = sz_flags;
   528 }
   529 
   530 int CForward::PushString(const char *string)
   531 {
   532 	if (m_curparam < m_numparams)
   533 	{
   534 		if (m_types[m_curparam] == Param_Any)
   535 		{
   536 			m_params[m_curparam].pushedas = Param_String;
   537 		} else if (m_types[m_curparam] != Param_String) {
   538 			return SetError(SP_ERROR_PARAM);
   539 		}
   540 	} else {
   541 		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
   542 		{
   543 			return SetError(SP_ERROR_PARAMS_MAX);
   544 		}
   545 		m_params[m_curparam].pushedas = Param_String;
   546 	}
   547 
   548 	_Int_PushString((cell_t *)string, strlen(string)+1, SM_PARAM_STRING_COPY, 0);
   549 	m_curparam++;
   550 
   551 	return SP_ERROR_NONE;
   552 }
   553 
   554 int CForward::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
   555 {
   556 	if (m_curparam < m_numparams)
   557 	{
   558 		if (m_types[m_curparam] == Param_Any)
   559 		{
   560 			m_params[m_curparam].pushedas = Param_String;
   561 		} else if (m_types[m_curparam] != Param_String) {
   562 			return SetError(SP_ERROR_PARAM);
   563 		}
   564 	} else {
   565 		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
   566 		{
   567 			return SetError(SP_ERROR_PARAMS_MAX);
   568 		}
   569 		m_params[m_curparam].pushedas = Param_String;
   570 	}
   571 
   572 	_Int_PushString((cell_t *)buffer, length, sz_flags, cp_flags);
   573 	m_curparam++;
   574 
   575 	return SP_ERROR_NONE;
   576 }
   577 
   578 void CForward::Cancel()
   579 {
   580 	if (!m_curparam)
   581 	{
   582 		return;
   583 	}
   584 
   585 	m_curparam = 0;
   586 	m_errstate = SP_ERROR_NONE;
   587 }
   588 
   589 bool CForward::AddFunction(IPluginContext *pContext, funcid_t index)
   590 {
   591 	IPluginFunction *pFunc = pContext->GetFunctionById(index);
   592 
   593 	if (!pFunc)
   594 	{
   595 		return false;
   596 	}
   597 
   598 	return AddFunction(pFunc);
   599 }
   600 
   601 bool CForward::RemoveFunction(IPluginFunction *func)
   602 {
   603 	bool found = false;
   604 	FuncIter iter;
   605 
   606 	for (iter=m_functions.begin(); iter!=m_functions.end();)
   607 	{
   608 		if ((*iter) == func)
   609 		{
   610 			found = true;
   611 			/* If this iterator is being used, swap in a new one !*/
   612 			iter = m_functions.erase(iter);
   613 		} else {
   614 			iter++;
   615 		}
   616 	}
   617 
   618 	/* Cancel a call, if any */
   619 	if (found || m_curparam)
   620 	{
   621 		func->Cancel();
   622 	}
   623 
   624 	return found;
   625 }
   626 
   627 unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin)
   628 {
   629 	FuncIter iter;
   630 	IPluginFunction *func;
   631 	unsigned int removed = 0;
   632 	IPluginContext *pContext = plugin->GetBaseContext();
   633 	for (iter=m_functions.begin(); iter!=m_functions.end();)
   634 	{
   635 		func = (*iter);
   636 		if (func->GetParentContext() == pContext)
   637 		{
   638 			iter = m_functions.erase(iter);
   639 			removed++;
   640 		} else {
   641 			iter++;
   642 		}
   643 	}
   644 
   645 	return removed;
   646 }
   647 
   648 bool CForward::AddFunction(IPluginFunction *func)
   649 {
   650 	if (m_curparam)
   651 	{
   652 		return false;
   653 	}
   654 
   655 	//:IDEA: eventually we will tell the plugin we're using it [?]
   656 	m_functions.push_back(func);
   657 
   658 	return true;
   659 }
   660 
   661 const char *CForward::GetForwardName()
   662 {
   663 	return m_name;
   664 }
   665 
   666 unsigned int CForward::GetFunctionCount()
   667 {
   668 	return m_functions.size();
   669 }
   670 
   671 ExecType CForward::GetExecType()
   672 {
   673 	return m_ExecType;
   674 }