core/systems/ForwardSys.cpp
author David Anderson <dvander@alliedmods.net>
Thu Jan 11 01:13:34 2007 +0000 (2007-01-11)
changeset 282 cd7c334f7ae0
parent 232 e489a0b1b736
child 288 d89bf250dac4
permissions -rw-r--r--
removed a few TODOs and filled out some PluginSys stuff
     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 
   259 		for (unsigned int i=0; i<num_params; i++)
   260 		{
   261 			param = &temp_info[i];
   262 			if (i >= m_numparams || m_types[i] == Param_Any)
   263 			{
   264 				type = param->pushedas;
   265 			} else {
   266 				type = m_types[i];
   267 			}
   268 			if ((i >= m_numparams) || (type & SP_PARAMFLAG_BYREF))
   269 			{
   270 				/* If we're byref or we're vararg, we always push everything by ref.
   271 				 * Even if they're byval, we must push them byref.
   272 				 */
   273 				if (type == Param_String)
   274 				{
   275 					func->PushStringEx((char *)param->byref.orig_addr, param->byref.cells, param->byref.sz_flags, param->byref.flags);
   276 				} else if (type == Param_Float || type == Param_Cell) {
   277 					func->PushCellByRef(&param->val, 0); 
   278 				} else {
   279 					func->PushArray(param->byref.orig_addr, param->byref.cells, NULL, param->byref.flags);
   280 					assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef);
   281 				}
   282 			} else {
   283 				/* If we're not byref or not vararg, our job is a bit easier. */
   284 				assert(type == Param_Cell || type == Param_Float);
   285 				func->PushCell(param->val);
   286 			}
   287 		}
   288 		
   289 		/* Call the function and deal with the return value. */
   290 		if ((err=func->Execute(&cur_result)) != SP_ERROR_NONE)
   291 		{
   292 			bool handled = false;
   293 			if (filter)
   294 			{
   295 				handled = filter->OnErrorReport(this, func, err);
   296 			}
   297 			if (!handled)
   298 			{
   299 				/* :TODO: invoke global error reporting here */
   300 			}
   301 			failed++;
   302 		} else {
   303 			success++;
   304 			switch (m_ExecType)
   305 			{
   306 			case ET_Event:
   307 				{
   308 					if (cur_result > high_result)
   309 					{
   310 						high_result = cur_result;
   311 					}
   312 					break;
   313 				}
   314 			case ET_Hook:
   315 				{
   316 					if (cur_result > high_result)
   317 					{
   318 						high_result = cur_result;
   319 						if ((ResultType)high_result == Pl_Stop)
   320 						{
   321 							iter = m_functions.end();
   322 							break;
   323 						}
   324 					}
   325 					break;
   326 				}
   327 			case ET_Custom:
   328 				{
   329 					if (filter)
   330 					{
   331 						if (filter->OnFunctionReturn(this, func, &cur_result) == Pl_Stop)
   332 						{
   333 							iter = m_functions.end();
   334 						}
   335 					}
   336 					break;
   337 				}
   338 			}
   339 		}
   340 	}
   341 
   342 	if (m_ExecType == ET_Event || m_ExecType == ET_Hook)
   343 	{
   344 		cur_result = high_result;
   345 	} else if (m_ExecType == ET_Ignore) {
   346 		cur_result = 0;
   347 	}
   348 
   349 	*result = cur_result;
   350 
   351 	if (filter)
   352 	{
   353 		filter->OnExecuteEnd(&cur_result, success, failed);
   354 	}
   355 
   356 	return SP_ERROR_NONE;
   357 }
   358 
   359 int CForward::PushCell(cell_t cell)
   360 {
   361 	if (m_curparam < m_numparams)
   362 	{
   363 		if (m_types[m_curparam] == Param_Any)
   364 		{
   365 			m_params[m_curparam].pushedas = Param_Cell;
   366 		} else if (m_types[m_curparam] != Param_Cell) {
   367 			return SetError(SP_ERROR_PARAM);
   368 		}
   369 	} else {
   370 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   371 		{
   372 			return SetError(SP_ERROR_PARAMS_MAX);
   373 		}
   374 		m_params[m_curparam].pushedas = Param_Cell;
   375 	}
   376 
   377 	m_params[m_curparam++].val = cell;
   378 
   379 	return SP_ERROR_NONE;
   380 }
   381 
   382 int CForward::PushFloat(float number)
   383 {
   384 	if (m_curparam < m_numparams)
   385 	{
   386 		if (m_types[m_curparam] == Param_Any)
   387 		{
   388 			m_params[m_curparam].pushedas = Param_Float;
   389 		} else if (m_types[m_curparam] != Param_Float) {
   390 			return SetError(SP_ERROR_PARAM);
   391 		}
   392 	} else {
   393 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   394 		{
   395 			return SetError(SP_ERROR_PARAMS_MAX);
   396 		}
   397 		m_params[m_curparam].pushedas = Param_Float;
   398 	}
   399 
   400 	m_params[m_curparam++].val = *(cell_t *)&number;
   401 
   402 	return SP_ERROR_NONE;
   403 }
   404 
   405 int CForward::PushCellByRef(cell_t *cell, int flags)
   406 {
   407 	if (m_curparam < m_numparams)
   408 	{
   409 		if (m_types[m_curparam] == Param_Any)
   410 		{
   411 			m_params[m_curparam].pushedas = Param_CellByRef;
   412 		} else if (m_types[m_curparam] != Param_CellByRef) {
   413 			return SetError(SP_ERROR_PARAM);
   414 		}
   415 	} else {
   416 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   417 		{
   418 			return SetError(SP_ERROR_PARAMS_MAX);
   419 		}
   420 		m_params[m_curparam].pushedas = Param_CellByRef;
   421 	}
   422 
   423 	_Int_PushArray(cell, 1, flags);
   424 	m_curparam++;
   425 
   426 	return SP_ERROR_NONE;
   427 }
   428 
   429 int CForward::PushFloatByRef(float *num, int flags)
   430 {
   431 	if (m_curparam < m_numparams)
   432 	{
   433 		if (m_types[m_curparam] == Param_Any)
   434 		{
   435 			m_params[m_curparam].pushedas = Param_FloatByRef;
   436 		} else if (m_types[m_curparam] != Param_FloatByRef) {
   437 			return SetError(SP_ERROR_PARAM);
   438 		}
   439 	} else {
   440 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   441 		{
   442 			return SetError(SP_ERROR_PARAMS_MAX);
   443 		}
   444 		m_params[m_curparam].pushedas = Param_FloatByRef;
   445 	}
   446 
   447 	_Int_PushArray((cell_t *)num, 1, flags);
   448 	m_curparam++;
   449 
   450 	return SP_ERROR_NONE;
   451 }
   452 
   453 void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags)
   454 {
   455 	m_params[m_curparam].byref.cells = cells;
   456 	m_params[m_curparam].byref.flags = flags;
   457 	m_params[m_curparam].byref.orig_addr = inarray;
   458 }
   459 
   460 int CForward::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int flags)
   461 {
   462 	/* We don't allow this here */
   463 	if (!inarray)
   464 	{
   465 		return SetError(SP_ERROR_PARAM);
   466 	}
   467 
   468 	if (m_curparam < m_numparams)
   469 	{
   470 		if (m_types[m_curparam] == Param_Any)
   471 		{
   472 			m_params[m_curparam].pushedas = Param_Array;
   473 		} else if (m_types[m_curparam] != Param_Array) {
   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 		m_params[m_curparam].pushedas = Param_Array;
   482 	}
   483 
   484 	if (phys_addr)
   485 	{
   486 		*phys_addr = NULL;
   487 	}
   488 
   489 	_Int_PushArray(inarray, cells, flags);
   490 
   491 	m_curparam++;
   492 
   493 	return SP_ERROR_NONE;
   494 }
   495 
   496 void CForward::_Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_flags)
   497 {
   498 	m_params[m_curparam].byref.cells = cells;	/* Notice this contains the char count not cell count */
   499 	m_params[m_curparam].byref.flags = cp_flags;
   500 	m_params[m_curparam].byref.orig_addr = inarray;
   501 	m_params[m_curparam].byref.sz_flags = sz_flags;
   502 }
   503 
   504 int CForward::PushString(const char *string)
   505 {
   506 	if (m_curparam < m_numparams)
   507 	{
   508 		if (m_types[m_curparam] == Param_Any)
   509 		{
   510 			m_params[m_curparam].pushedas = Param_String;
   511 		} else if (m_types[m_curparam] != Param_String) {
   512 			return SetError(SP_ERROR_PARAM);
   513 		}
   514 	} else {
   515 		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
   516 		{
   517 			return SetError(SP_ERROR_PARAMS_MAX);
   518 		}
   519 		m_params[m_curparam].pushedas = Param_String;
   520 	}
   521 
   522 	_Int_PushString((cell_t *)string, strlen(string)+1, SM_PARAM_STRING_COPY, 0);
   523 	m_curparam++;
   524 
   525 	return SP_ERROR_NONE;
   526 }
   527 
   528 int CForward::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
   529 {
   530 	if (m_curparam < m_numparams)
   531 	{
   532 		if (m_types[m_curparam] == Param_Any)
   533 		{
   534 			m_params[m_curparam].pushedas = Param_String;
   535 		} else if (m_types[m_curparam] != Param_String) {
   536 			return SetError(SP_ERROR_PARAM);
   537 		}
   538 	} else {
   539 		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
   540 		{
   541 			return SetError(SP_ERROR_PARAMS_MAX);
   542 		}
   543 		m_params[m_curparam].pushedas = Param_String;
   544 	}
   545 
   546 	_Int_PushString((cell_t *)buffer, length, sz_flags, cp_flags);
   547 	m_curparam++;
   548 
   549 	return SP_ERROR_NONE;
   550 }
   551 
   552 void CForward::Cancel()
   553 {
   554 	if (!m_curparam)
   555 	{
   556 		return;
   557 	}
   558 
   559 	m_curparam = 0;
   560 	m_errstate = SP_ERROR_NONE;
   561 }
   562 
   563 bool CForward::AddFunction(sp_context_t *ctx, funcid_t index)
   564 {
   565 	IPlugin *pPlugin = g_PluginSys.FindPluginByContext(ctx);
   566 	if (!pPlugin)
   567 	{
   568 		return false;
   569 	}
   570 
   571 	IPluginFunction *pFunc = pPlugin->GetFunctionById(index);
   572 	if (!pFunc)
   573 	{
   574 		return false;
   575 	}
   576 
   577 	return AddFunction(pFunc);
   578 }
   579 
   580 bool CForward::RemoveFunction(IPluginFunction *func)
   581 {
   582 	bool found = false;
   583 	FuncIter iter;
   584 	IPluginFunction *pNext = NULL;
   585 
   586 	for (iter=m_functions.begin(); iter!=m_functions.end();)
   587 	{
   588 		if ((*iter) == func)
   589 		{
   590 			found = true;
   591 			/* If this iterator is being used, swap in a new one !*/
   592 			iter = m_functions.erase(iter);
   593 		} else {
   594 			iter++;
   595 		}
   596 	}
   597 
   598 	/* Cancel a call, if any */
   599 	if (found || m_curparam)
   600 	{
   601 		func->Cancel();
   602 	}
   603 
   604 	return found;
   605 }
   606 
   607 unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin)
   608 {
   609 	FuncIter iter;
   610 	IPluginFunction *func;
   611 	unsigned int removed = 0;
   612 	for (iter=m_functions.begin(); iter!=m_functions.end();)
   613 	{
   614 		func = (*iter);
   615 		if (func->GetParentPlugin() == plugin)
   616 		{
   617 			iter = m_functions.erase(iter);
   618 			removed++;
   619 		} else {
   620 			iter++;
   621 		}
   622 	}
   623 
   624 	return removed;
   625 }
   626 
   627 bool CForward::AddFunction(IPluginFunction *func)
   628 {
   629 	if (m_curparam)
   630 	{
   631 		return false;
   632 	}
   633 
   634 	//:IDEA: eventually we will tell the plugin we're using it [?]
   635 	m_functions.push_back(func);
   636 
   637 	return true;
   638 }
   639 
   640 const char *CForward::GetForwardName()
   641 {
   642 	return m_name;
   643 }
   644 
   645 unsigned int CForward::GetFunctionCount()
   646 {
   647 	return m_functions.size();
   648 }
   649 
   650 ExecType CForward::GetExecType()
   651 {
   652 	return m_ExecType;
   653 }