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