core/systems/ForwardSys.cpp
author David Anderson <dvander@alliedmods.net>
Sun Nov 12 01:06:17 2006 +0000 (2006-11-12)
changeset 180 fe406c5f2aeb
child 181 1e1570518051
permissions -rw-r--r--
Initial import of forward system
     1 #include <assert.h>
     2 #include "ForwardSys.h"
     3 #include "PluginSys.h"
     4 
     5 CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int num_params, ParamType *types, va_list ap)
     6 {
     7 	ParamType _types[SP_MAX_EXEC_PARAMS];
     8 
     9 	if (num_params > SP_MAX_EXEC_PARAMS)
    10 	{
    11 		return NULL;
    12 	}
    13 	
    14 	if (types == NULL && num_params)
    15 	{
    16 		for (unsigned int i=0; i<num_params; i++)
    17 		{
    18 			_types[i] = va_arg(ap, ParamType);
    19 			if (_types[i] == Param_VarArgs && (i != num_params - 1))
    20 			{
    21 				return NULL;
    22 			}
    23 		}
    24 		types = _types;
    25 	} else {
    26 		for (unsigned int i=0; i<num_params; i++)
    27 		{
    28 			if (types[i] == Param_VarArgs && (i != num_params - 1))
    29 			{
    30 				return NULL;
    31 			}
    32 		}
    33 	}
    34 
    35 	/* First parameter can never be varargs */
    36 	if (types[0] == Param_VarArgs)
    37 	{
    38 		return NULL;
    39 	}
    40 
    41 	CForward *pForward = new CForward;
    42 	pForward->m_curparam = 0;
    43 	pForward->m_ExecType = et;
    44 	snprintf(pForward->m_name, FORWARDS_NAME_MAX, "%s", name ? name : "");
    45 	
    46 	for (unsigned int i=0; i<num_params; i++)
    47 	{
    48 		pForward->m_types[i] = types[i];
    49 	}
    50 
    51 	if (num_params && types[num_params-1] == Param_VarArgs)
    52 	{
    53 		pForward->m_varargs = true;
    54 	} else {
    55 		pForward->m_varargs = false;
    56 	}
    57 
    58 	pForward->m_numparams = num_params;
    59 	pForward->m_errstate = SP_ERROR_NONE;
    60 	pForward->m_CopyBacks.numrecopy = 0;
    61 
    62 	return pForward;
    63 }
    64 
    65 bool CForward::OnCopybackArray(unsigned int param, 
    66 							   unsigned int cells, 
    67 							   cell_t *source_addr, 
    68 							   cell_t *orig_addr, 
    69 							   int flags)
    70 {
    71 	/* Check if the stack is empty, this should be an assertion */
    72 	if (m_NextStack.empty())
    73 	{
    74 		/* This should never happen! */
    75 		assert(!m_NextStack.empty());
    76 		return true;
    77 	}
    78 
    79 	/* Check if we even want to copy to the next plugin */
    80 	if (!(flags & SMFUNC_COPYBACK_ALWAYS))
    81 	{
    82 		return true;
    83 	}
    84 
    85 	/* Keep track of the copy back and save the info */
    86 	NextCallInfo &info = m_NextStack.front();
    87 	info.recopy[info.numrecopy++] = param;
    88 	info.orig_addrs[param] = orig_addr;
    89 	info.sizes[param] = cells;
    90 
    91 	/* We don't want to override the copy. */
    92 	return true;
    93 }
    94 
    95 int CForward::Execute(cell_t *result, IForwardFilter *filter)
    96 {
    97 	if (m_errstate)
    98 	{
    99 		int err = m_errstate;
   100 		Cancel();
   101 		return err;
   102 	}
   103 
   104 	/* Reset marker */
   105 	m_curparam = 0;
   106 
   107 	if (filter)
   108 	{
   109 		filter->OnExecuteBegin();
   110 	}
   111 
   112 	FuncIter iter = m_functions.begin();
   113 	IPluginFunction *func;
   114 	cell_t cur_result = 0;
   115 	cell_t high_result = 0;
   116 	int err;
   117 	unsigned int failed=0, success=0;
   118 	unsigned int save_numcopy = 0;
   119 
   120 	/** 
   121 	 * Save copyback into to start the chain, 
   122 	 * then reset it for re-entrancy
   123 	 */
   124 	m_NextStack.push(m_CopyBacks);
   125 	NextCallInfo &info = m_NextStack.front();
   126 	m_CopyBacks.numrecopy = 0;
   127 	
   128 	for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
   129 	{
   130 		func = (*iter);
   131 		
   132 		/**
   133 		 * Check if we need to copy a new array back into the plugin.
   134 		 */
   135 		if (info.numrecopy)
   136 		{
   137 			/* The last plugin has a chained copyback, we must redirect it here. */
   138 			unsigned int param;
   139 			cell_t *orig_addr, *targ_addr;
   140 			for (unsigned int i=0; i<info.numrecopy; i++)
   141 			{
   142 				/* Get the parameter info to copy */
   143 				param = info.recopy[i];
   144 				targ_addr = func->GetAddressOfPushedParam(param);
   145 				orig_addr = info.orig_addrs[param];
   146 				/* Only do the copy for valid targets */
   147 				if (targ_addr && orig_addr)
   148 				{
   149 					if (info.sizes[param] == 1)
   150 					{
   151 						*targ_addr = *orig_addr;
   152 					} else {
   153 						memcpy(targ_addr, orig_addr, info.sizes[param] * sizeof(cell_t));
   154 					}
   155 				}
   156 				/* If this failed, the plugin will most likely be failing as well. */
   157 			}
   158 			save_numcopy = info.numrecopy;
   159 			info.numrecopy = 0;
   160 		}
   161 
   162 		/* Call the function and deal with the return value.
   163 		 * :TODO: only pass reader if we know we have an array in the list
   164 		 */
   165 		if ((err=func->Execute(&cur_result, this)) != SP_ERROR_NONE)
   166 		{
   167 			bool handled = false;
   168 			if (filter)
   169 			{
   170 				handled = filter->OnErrorReport(this, func, err);
   171 			}
   172 			if (!handled)
   173 			{
   174 				/* :TODO: invoke global error reporting here */
   175 			}
   176 			/* If we failed, we're not quite done.  The copy chain has been broken.
   177 			 * We have to restore it so past changes will continue to get mirrored.
   178 			 */
   179 			info.numrecopy = save_numcopy;
   180 			failed++;
   181 		} else {
   182 			success++;
   183 			switch (m_ExecType)
   184 			{
   185 			case ET_Event:
   186 				{
   187 					if (cur_result > high_result)
   188 					{
   189 						high_result = cur_result;
   190 					}
   191 					break;
   192 				}
   193 			case ET_Hook:
   194 				{
   195 					if (cur_result > high_result)
   196 					{
   197 						high_result = cur_result;
   198 						if ((ResultType)high_result == Pl_Stop)
   199 						{
   200 							iter = m_functions.end();
   201 							break;
   202 						}
   203 					}
   204 					break;
   205 				}
   206 			case ET_Custom:
   207 				{
   208 					if (filter)
   209 					{
   210 						if (filter->OnFunctionReturn(this, func, &cur_result) == Pl_Stop)
   211 						{
   212 							iter = m_functions.end();
   213 						}
   214 					}
   215 					break;
   216 				}
   217 			}
   218 		}
   219 	}
   220 
   221 	m_NextStack.pop();
   222 
   223 	if (m_ExecType == ET_Event || m_ExecType == ET_Hook)
   224 	{
   225 		cur_result = high_result;
   226 	} else if (m_ExecType == ET_Ignore) {
   227 		cur_result = 0;
   228 	}
   229 
   230 	*result = cur_result;
   231 
   232 	DumpAdditionQueue();
   233 
   234 	if (filter)
   235 	{
   236 		filter->OnExecuteEnd(&cur_result, success, failed);
   237 	}
   238 
   239 	return SP_ERROR_NONE;
   240 }
   241 
   242 int CForward::PushCell(cell_t cell)
   243 {
   244 	if (m_curparam < m_numparams)
   245 	{
   246 		if (m_types[m_curparam] != Param_Cell && m_types[m_curparam] != Param_Any)
   247 		{
   248 			return SetError(SP_ERROR_PARAM);
   249 		}
   250 	} else {
   251 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   252 		{
   253 			return SetError(SP_ERROR_PARAMS_MAX);
   254 		}
   255 	}
   256 
   257 	FuncIter iter;
   258 	IPluginFunction *func;
   259 	for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
   260 	{
   261 		func = (*iter);
   262 		func->PushCell(cell);
   263 	}
   264 
   265 	m_curparam++;
   266 
   267 	return SP_ERROR_NONE;
   268 }
   269 
   270 int CForward::PushFloat(float number)
   271 {
   272 	if (m_curparam < m_numparams)
   273 	{
   274 		if (m_types[m_curparam] != Param_Float && m_types[m_curparam] != Param_Any)
   275 		{
   276 			return SetError(SP_ERROR_PARAM);
   277 		}
   278 	} else {
   279 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   280 		{
   281 			return SetError(SP_ERROR_PARAMS_MAX);
   282 		}
   283 	}
   284 
   285 	FuncIter iter;
   286 	IPluginFunction *func;
   287 	for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
   288 	{
   289 		func = (*iter);
   290 		func->PushFloat(number);
   291 	}
   292 
   293 	m_curparam++;
   294 
   295 	return SP_ERROR_NONE;
   296 }
   297 
   298 int CForward::PushCellByRef(cell_t *cell, int flags)
   299 {
   300 	if (m_curparam < m_numparams)
   301 	{
   302 		if (m_types[m_curparam] != Param_CellByRef && m_types[m_curparam] != Param_Any)
   303 		{
   304 			return SetError(SP_ERROR_PARAM);
   305 		}
   306 	} else {
   307 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   308 		{
   309 			return SetError(SP_ERROR_PARAMS_MAX);
   310 		}
   311 	}
   312 
   313 	if (flags & SMFUNC_COPYBACK_ALWAYS)
   314 	{
   315 		_Int_PushArray(cell, 1, flags);
   316 	} else {
   317 		FuncIter iter;
   318 		IPluginFunction *func;
   319 		for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
   320 		{
   321 			func = (*iter);
   322 			func->PushCellByRef(cell, flags);
   323 		}
   324 	}
   325 
   326 	m_curparam++;
   327 
   328 	return SP_ERROR_NONE;
   329 }
   330 
   331 int CForward::PushFloatByRef(float *num, int flags)
   332 {
   333 	if (m_curparam < m_numparams)
   334 	{
   335 		if (m_types[m_curparam] != Param_FloatByRef && m_types[m_curparam] != Param_Any)
   336 		{
   337 			return SetError(SP_ERROR_PARAM);
   338 		}
   339 	} else {
   340 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   341 		{
   342 			return SetError(SP_ERROR_PARAMS_MAX);
   343 		}
   344 	}
   345 
   346 	if (flags & SMFUNC_COPYBACK_ALWAYS)
   347 	{
   348 		_Int_PushArray((cell_t *)num, 1, flags);
   349 	} else {
   350 		FuncIter iter;
   351 		IPluginFunction *func;
   352 		for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
   353 		{
   354 			func = (*iter);
   355 			func->PushFloatByRef(num, flags);
   356 		}
   357 	}
   358 
   359 	m_curparam++;
   360 
   361 	return SP_ERROR_NONE;
   362 }
   363 
   364 int CForward::PushCells(cell_t array[], unsigned int numcells, bool each)
   365 {
   366 	if (each)
   367 	{
   368 		/* Type check each cell if we need to! */
   369 		if (m_curparam + numcells >= m_numparams && !m_varargs)
   370 		{
   371 			return SetError(SP_ERROR_PARAMS_MAX);
   372 		} else {
   373 			for (unsigned int i=m_curparam; i<m_numparams; i++)
   374 			{
   375 				if (m_types[i] != Param_Any || m_types[i] != Param_Cell)
   376 				{
   377 					return SetError(SP_ERROR_PARAM);
   378 				}
   379 			}
   380 		}
   381 	} else {
   382 		if (m_curparam < m_numparams)
   383 		{
   384 			if (m_types[m_curparam] != Param_Any || m_types[m_curparam] == Param_Array)
   385 			{
   386 				return SetError(SP_ERROR_PARAM);
   387 			}
   388 		} else {
   389 			if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
   390 			{
   391 				return SetError(SP_ERROR_PARAMS_MAX);
   392 			}
   393 		}
   394 	}
   395 
   396 	FuncIter iter;
   397 	IPluginFunction *func;
   398 	for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
   399 	{
   400 		func = (*iter);
   401 		func->PushCells(array, numcells, each);
   402 	}
   403 
   404 	m_curparam += each ? numcells : 1;
   405 	
   406 	return SP_ERROR_NONE;
   407 }
   408 
   409 void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags)
   410 {
   411 	FuncIter iter;
   412 	IPluginFunction *func;
   413 	if (flags & SMFUNC_COPYBACK_ALWAYS)
   414 	{
   415 		/* As a special optimization, we create blank default arrays because they will be 
   416 		* copied over anyway!
   417 		*/
   418 		for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
   419 		{
   420 			func = (*iter);
   421 			func->PushArray(NULL, cells, NULL, flags);
   422 		}
   423 		m_CopyBacks.recopy[m_CopyBacks.numrecopy++] = m_curparam;
   424 		m_CopyBacks.orig_addrs[m_curparam] = inarray;
   425 		m_CopyBacks.sizes[m_curparam] = cells;
   426 	} else {
   427 		for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
   428 		{
   429 			func = (*iter);
   430 			func->PushArray(inarray, cells, NULL, flags);
   431 		}
   432 	}
   433 }
   434 
   435 int CForward::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int flags)
   436 {
   437 	/* We don't allow this here */
   438 	if (!inarray)
   439 	{
   440 		return SetError(SP_ERROR_PARAM);
   441 	}
   442 
   443 	if (m_curparam < m_numparams)
   444 	{
   445 		if (m_types[m_curparam] != Param_Any || m_types[m_curparam] == Param_Array)
   446 		{
   447 			return SetError(SP_ERROR_PARAM);
   448 		}
   449 	} else {
   450 		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
   451 		{
   452 			return SetError(SP_ERROR_PARAMS_MAX);
   453 		}
   454 	}
   455 
   456 	if (phys_addr)
   457 	{
   458 		*phys_addr = NULL;
   459 	}
   460 
   461 	_Int_PushArray(inarray, cells, flags);
   462 
   463 	m_curparam++;
   464 
   465 	return SP_ERROR_NONE;
   466 }
   467 
   468 int CForward::PushString(const char *string)
   469 {
   470 	if (m_curparam < m_numparams)
   471 	{
   472 		if (m_types[m_curparam] != Param_Any || m_types[m_curparam] == Param_String)
   473 		{
   474 			return SetError(SP_ERROR_PARAM);
   475 		}
   476 	} else {
   477 		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
   478 		{
   479 			return SetError(SP_ERROR_PARAMS_MAX);
   480 		}
   481 	}
   482 
   483 	FuncIter iter;
   484 	IPluginFunction *func;
   485 	for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
   486 	{
   487 		func = (*iter);
   488 		func->PushString(string);
   489 	}
   490 
   491 	m_curparam++;
   492 
   493 	return SP_ERROR_NONE;
   494 }
   495 
   496 int CForward::PushStringByRef(char *string, int flags)
   497 {
   498 	if (m_curparam < m_numparams)
   499 	{
   500 		if (m_types[m_curparam] != Param_Any || m_types[m_curparam] == Param_String)
   501 		{
   502 			return SetError(SP_ERROR_PARAM);
   503 		}
   504 	} else {
   505 		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
   506 		{
   507 			return SetError(SP_ERROR_PARAMS_MAX);
   508 		}
   509 	}
   510 
   511 	FuncIter iter;
   512 	IPluginFunction *func;
   513 	for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
   514 	{
   515 		func = (*iter);
   516 		func->PushStringByRef(string, flags);
   517 	}
   518 
   519 	m_curparam++;
   520 
   521 	return SP_ERROR_NONE;
   522 }
   523 
   524 void CForward::Cancel()
   525 {
   526 	if (!m_curparam)
   527 	{
   528 		return;
   529 	}
   530 
   531 	FuncIter iter;
   532 	IPluginFunction *func;
   533 	for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
   534 	{
   535 		func = (*iter);
   536 		func->Cancel();
   537 	}
   538 
   539 	m_CopyBacks.numrecopy = 0;
   540 
   541 	DumpAdditionQueue();
   542 
   543 	m_errstate = SP_ERROR_NONE;
   544 }
   545 
   546 bool CForward::AddFunction(sp_context_t *ctx, funcid_t index)
   547 {
   548 	IPlugin *pPlugin = g_PluginMngr.FindPluginByContext(ctx);
   549 	if (!pPlugin)
   550 	{
   551 		return false;
   552 	}
   553 
   554 	IPluginFunction *pFunc = pPlugin->GetFunctionById(index);
   555 	if (!pFunc)
   556 	{
   557 		return false;
   558 	}
   559 
   560 	return AddFunction(pFunc);
   561 }
   562 
   563 bool CForward::RemoveFunction(IPluginFunction *func)
   564 {
   565 	bool found = false;
   566 	FuncIter iter;
   567 	IPluginFunction *pNext = NULL;
   568 
   569 	for (iter=m_functions.begin(); iter!=m_functions.end();)
   570 	{
   571 		if ((*iter) == func)
   572 		{
   573 			found = true;
   574 			/* If this iterator is being used, swap in a new one !*/
   575 			iter = m_functions.erase(iter);
   576 		} else {
   577 			iter++;
   578 		}
   579 	}
   580 
   581 	/* Just in case */
   582 	m_AddQueue.remove(func);
   583 	
   584 	/* Cancel a call, if any */
   585 	if (found && (!m_NextStack.empty() || m_curparam))
   586 	{
   587 		func->Cancel();
   588 	}
   589 
   590 	return found;
   591 }
   592 
   593 unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin)
   594 {
   595 	FuncIter iter;
   596 	IPluginFunction *func;
   597 	unsigned int removed = 0;
   598 	for (iter=m_functions.begin(); iter!=m_functions.end();)
   599 	{
   600 		func = (*iter);
   601 		if (func->GetParentPlugin() == plugin)
   602 		{
   603 			iter = m_functions.erase(iter);
   604 			removed++;
   605 		} else {
   606 			iter++;
   607 		}
   608 	}
   609 
   610 	for (iter=m_AddQueue.begin(); iter!=m_AddQueue.end();)
   611 	{
   612 		func = (*iter);
   613 		if (func->GetParentPlugin() == plugin)
   614 		{
   615 			/* Don't count these toward the total */
   616 			iter = m_functions.erase(iter);
   617 		} else {
   618 			iter++;
   619 		}
   620 	}
   621 
   622 	return removed;
   623 }
   624 
   625 void CForward::DumpAdditionQueue()
   626 {
   627 	FuncIter iter = m_AddQueue.begin();
   628 	while (iter != m_AddQueue.end())
   629 	{
   630 		m_functions.push_back((*iter));
   631 		//:TODO: eventually we will tell the plugin we're using it
   632 		iter = m_AddQueue.erase(iter);
   633 	}
   634 }
   635 
   636 bool CForward::AddFunction(IPluginFunction *func)
   637 {
   638 	if (m_curparam)
   639 	{
   640 		return false;
   641 	}
   642 
   643 	if (!m_NextStack.empty())
   644 	{
   645 		m_AddQueue.push_back(func);
   646 	} else {
   647 		//:TODO: eventually we will tell the plugin we're using it
   648 		m_functions.push_back(func);
   649 	}
   650 
   651 	return true;
   652 }
   653 
   654 const char *CForward::GetForwardName()
   655 {
   656 	return m_name;
   657 }
   658 
   659 unsigned int CForward::GetFunctionCount()
   660 {
   661 	return m_functions.size();
   662 }
   663 
   664 ExecType CForward::GetExecType()
   665 {
   666 	return m_ExecType;
   667 }