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