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