core/systems/ForwardSys.cpp
author David Anderson <dvander@alliedmods.net>
Wed Jan 17 06:49:59 2007 +0000 (2007-01-17)
changeset 308 f0e65f92cb34
parent 291 345d084ae151
child 327 e244337a9b38
permissions -rw-r--r--
Redesigned how server commands work. The "plugins" command will be back soon.
     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 	m_managed.remove(fwd);
   148 }
   149 
   150 CForward *CForwardManager::ForwardMake()
   151 {
   152 	CForward *fwd;
   153 	if (m_FreeForwards.empty())
   154 	{
   155 		fwd = new CForward;
   156 	} else {
   157 		fwd = m_FreeForwards.front();
   158 		m_FreeForwards.pop();
   159 	}
   160 	return fwd;
   161 }
   162 
   163 /*************************************
   164  * ACTUAL FORWARD API IMPLEMENTATION *
   165  *************************************/
   166 
   167 CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int num_params, ParamType *types, va_list ap)
   168 {
   169 	ParamType _types[SP_MAX_EXEC_PARAMS];
   170 
   171 	if (num_params > SP_MAX_EXEC_PARAMS)
   172 	{
   173 		return NULL;
   174 	}
   175 	
   176 	if (types == NULL && num_params)
   177 	{
   178 		for (unsigned int i=0; i<num_params; i++)
   179 		{
   180 			_types[i] = va_arg(ap, ParamType);
   181 			if (_types[i] == Param_VarArgs && (i != num_params - 1))
   182 			{
   183 				return NULL;
   184 			}
   185 		}
   186 		types = _types;
   187 	} else {
   188 		for (unsigned int i=0; i<num_params; i++)
   189 		{
   190 			if (types[i] == Param_VarArgs && (i != num_params - 1))
   191 			{
   192 				return NULL;
   193 			}
   194 		}
   195 	}
   196 
   197 	/* First parameter can never be varargs */
   198 	if (types[0] == Param_VarArgs)
   199 	{
   200 		return NULL;
   201 	}
   202 
   203 	CForward *pForward = g_Forwards.ForwardMake();
   204 	pForward->m_curparam = 0;
   205 	pForward->m_ExecType = et;
   206 	snprintf(pForward->m_name, FORWARDS_NAME_MAX, "%s", name ? name : "");
   207 	
   208 	for (unsigned int i=0; i<num_params; i++)
   209 	{
   210 		pForward->m_types[i] = types[i];
   211 	}
   212 
   213 	if (num_params && types[num_params-1] == Param_VarArgs)
   214 	{
   215 		pForward->m_varargs = num_params--;
   216 	} else {
   217 		pForward->m_varargs = false;
   218 	}
   219 
   220 	pForward->m_numparams = num_params;
   221 	pForward->m_errstate = SP_ERROR_NONE;
   222 
   223 	return pForward;
   224 }
   225 
   226 int CForward::Execute(cell_t *result, IForwardFilter *filter)
   227 {
   228 	if (m_errstate)
   229 	{
   230 		int err = m_errstate;
   231 		Cancel();
   232 		return err;
   233 	}
   234 
   235 	if (filter)
   236 	{
   237 		filter->OnExecuteBegin();
   238 	}
   239 
   240 	FuncIter iter = m_functions.begin();
   241 	IPluginFunction *func;
   242 	cell_t cur_result = 0;
   243 	cell_t high_result = 0;
   244 	int err;
   245 	unsigned int failed=0, success=0;
   246 	unsigned int save_numcopy = 0;
   247 	unsigned int num_params = m_curparam;
   248 	FwdParamInfo temp_info[SP_MAX_EXEC_PARAMS];
   249 	FwdParamInfo *param;
   250 	ParamType type;
   251 
   252 	/* Save local, reset */
   253 	memcpy(temp_info, m_params, sizeof(m_params));
   254 	m_curparam = 0;
   255 
   256 	for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
   257 	{
   258 		func = (*iter);
   259 		if (func->GetParentPlugin()->GetStatus() == Plugin_Paused)
   260 		{
   261 			continue;
   262 		}
   263 
   264 		for (unsigned int i=0; i<num_params; i++)
   265 		{
   266 			param = &temp_info[i];
   267 			if (i >= m_numparams || m_types[i] == Param_Any)
   268 			{
   269 				type = param->pushedas;
   270 			} else {
   271 				type = m_types[i];
   272 			}
   273 			if ((i >= m_numparams) || (type & SP_PARAMFLAG_BYREF))
   274 			{
   275 				/* If we're byref or we're vararg, we always push everything by ref.
   276 				 * Even if they're byval, we must push them byref.
   277 				 */
   278 				if (type == Param_String)
   279 				{
   280 					func->PushStringEx((char *)param->byref.orig_addr, param->byref.cells, param->byref.sz_flags, param->byref.flags);
   281 				} else if (type == Param_Float || type == Param_Cell) {
   282 					func->PushCellByRef(&param->val, 0); 
   283 				} else {
   284 					func->PushArray(param->byref.orig_addr, param->byref.cells, NULL, param->byref.flags);
   285 					assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef);
   286 				}
   287 			} else {
   288 				/* If we're not byref or not vararg, our job is a bit easier. */
   289 				assert(type == Param_Cell || type == Param_Float);
   290 				func->PushCell(param->val);
   291 			}
   292 		}
   293 		
   294 		/* Call the function and deal with the return value. */
   295 		if ((err=func->Execute(&cur_result)) != SP_ERROR_NONE)
   296 		{
   297 			bool handled = false;
   298 			if (filter)
   299 			{
   300 				handled = filter->OnErrorReport(this, func, err);
   301 			}
   302 			if (!handled)
   303 			{
   304 				/* :TODO: invoke global error reporting here */
   305 			}
   306 			failed++;
   307 		} else {
   308 			success++;
   309 			switch (m_ExecType)
   310 			{
   311 			case ET_Event:
   312 				{
   313 					if (cur_result > high_result)
   314 					{
   315 						high_result = cur_result;
   316 					}
   317 					break;
   318 				}
   319 			case ET_Hook:
   320 				{
   321 					if (cur_result > high_result)
   322 					{
   323 						high_result = cur_result;
   324 						if ((ResultType)high_result == Pl_Stop)
   325 						{
   326 							iter = m_functions.end();
   327 							break;
   328 						}
   329 					}
   330 					break;
   331 				}
   332 			case ET_Custom:
   333 				{
   334 					if (filter)
   335 					{
   336 						if (filter->OnFunctionReturn(this, func, &cur_result) == Pl_Stop)
   337 						{
   338 							iter = m_functions.end();
   339 						}
   340 					}
   341 					break;
   342 				}
   343 			}
   344 		}
   345 	}
   346 
   347 	if (m_ExecType == ET_Event || m_ExecType == ET_Hook)
   348 	{
   349 		cur_result = high_result;
   350 	} else if (m_ExecType == ET_Ignore) {
   351 		cur_result = 0;
   352 	}
   353 
   354 	*result = cur_result;
   355 
   356 	if (filter)
   357 	{
   358 		filter->OnExecuteEnd(&cur_result, success, failed);
   359 	}
   360 
   361 	return SP_ERROR_NONE;
   362 }
   363 
   364 int CForward::PushCell(cell_t cell)
   365 {
   366 	if (m_curparam < m_numparams)
   367 	{
   368 		if (m_types[m_curparam] == Param_Any)
   369 		{
   370 			m_params[m_curparam].pushedas = Param_Cell;
   371 		} else if (m_types[m_curparam] != Param_Cell) {
   372 			return SetError(SP_ERROR_PARAM);
   373 		}
   374 	} else {
   375 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   376 		{
   377 			return SetError(SP_ERROR_PARAMS_MAX);
   378 		}
   379 		m_params[m_curparam].pushedas = Param_Cell;
   380 	}
   381 
   382 	m_params[m_curparam++].val = cell;
   383 
   384 	return SP_ERROR_NONE;
   385 }
   386 
   387 int CForward::PushFloat(float number)
   388 {
   389 	if (m_curparam < m_numparams)
   390 	{
   391 		if (m_types[m_curparam] == Param_Any)
   392 		{
   393 			m_params[m_curparam].pushedas = Param_Float;
   394 		} else if (m_types[m_curparam] != Param_Float) {
   395 			return SetError(SP_ERROR_PARAM);
   396 		}
   397 	} else {
   398 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   399 		{
   400 			return SetError(SP_ERROR_PARAMS_MAX);
   401 		}
   402 		m_params[m_curparam].pushedas = Param_Float;
   403 	}
   404 
   405 	m_params[m_curparam++].val = *(cell_t *)&number;
   406 
   407 	return SP_ERROR_NONE;
   408 }
   409 
   410 int CForward::PushCellByRef(cell_t *cell, int flags)
   411 {
   412 	if (m_curparam < m_numparams)
   413 	{
   414 		if (m_types[m_curparam] == Param_Any)
   415 		{
   416 			m_params[m_curparam].pushedas = Param_CellByRef;
   417 		} else if (m_types[m_curparam] != Param_CellByRef) {
   418 			return SetError(SP_ERROR_PARAM);
   419 		}
   420 	} else {
   421 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   422 		{
   423 			return SetError(SP_ERROR_PARAMS_MAX);
   424 		}
   425 		m_params[m_curparam].pushedas = Param_CellByRef;
   426 	}
   427 
   428 	_Int_PushArray(cell, 1, flags);
   429 	m_curparam++;
   430 
   431 	return SP_ERROR_NONE;
   432 }
   433 
   434 int CForward::PushFloatByRef(float *num, int flags)
   435 {
   436 	if (m_curparam < m_numparams)
   437 	{
   438 		if (m_types[m_curparam] == Param_Any)
   439 		{
   440 			m_params[m_curparam].pushedas = Param_FloatByRef;
   441 		} else if (m_types[m_curparam] != Param_FloatByRef) {
   442 			return SetError(SP_ERROR_PARAM);
   443 		}
   444 	} else {
   445 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   446 		{
   447 			return SetError(SP_ERROR_PARAMS_MAX);
   448 		}
   449 		m_params[m_curparam].pushedas = Param_FloatByRef;
   450 	}
   451 
   452 	_Int_PushArray((cell_t *)num, 1, flags);
   453 	m_curparam++;
   454 
   455 	return SP_ERROR_NONE;
   456 }
   457 
   458 void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags)
   459 {
   460 	m_params[m_curparam].byref.cells = cells;
   461 	m_params[m_curparam].byref.flags = flags;
   462 	m_params[m_curparam].byref.orig_addr = inarray;
   463 }
   464 
   465 int CForward::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int flags)
   466 {
   467 	/* We don't allow this here */
   468 	if (!inarray)
   469 	{
   470 		return SetError(SP_ERROR_PARAM);
   471 	}
   472 
   473 	if (m_curparam < m_numparams)
   474 	{
   475 		if (m_types[m_curparam] == Param_Any)
   476 		{
   477 			m_params[m_curparam].pushedas = Param_Array;
   478 		} else if (m_types[m_curparam] != Param_Array) {
   479 			return SetError(SP_ERROR_PARAM);
   480 		}
   481 	} else {
   482 		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
   483 		{
   484 			return SetError(SP_ERROR_PARAMS_MAX);
   485 		}
   486 		m_params[m_curparam].pushedas = Param_Array;
   487 	}
   488 
   489 	if (phys_addr)
   490 	{
   491 		*phys_addr = NULL;
   492 	}
   493 
   494 	_Int_PushArray(inarray, cells, flags);
   495 
   496 	m_curparam++;
   497 
   498 	return SP_ERROR_NONE;
   499 }
   500 
   501 void CForward::_Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_flags)
   502 {
   503 	m_params[m_curparam].byref.cells = cells;	/* Notice this contains the char count not cell count */
   504 	m_params[m_curparam].byref.flags = cp_flags;
   505 	m_params[m_curparam].byref.orig_addr = inarray;
   506 	m_params[m_curparam].byref.sz_flags = sz_flags;
   507 }
   508 
   509 int CForward::PushString(const char *string)
   510 {
   511 	if (m_curparam < m_numparams)
   512 	{
   513 		if (m_types[m_curparam] == Param_Any)
   514 		{
   515 			m_params[m_curparam].pushedas = Param_String;
   516 		} else if (m_types[m_curparam] != Param_String) {
   517 			return SetError(SP_ERROR_PARAM);
   518 		}
   519 	} else {
   520 		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
   521 		{
   522 			return SetError(SP_ERROR_PARAMS_MAX);
   523 		}
   524 		m_params[m_curparam].pushedas = Param_String;
   525 	}
   526 
   527 	_Int_PushString((cell_t *)string, strlen(string)+1, SM_PARAM_STRING_COPY, 0);
   528 	m_curparam++;
   529 
   530 	return SP_ERROR_NONE;
   531 }
   532 
   533 int CForward::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
   534 {
   535 	if (m_curparam < m_numparams)
   536 	{
   537 		if (m_types[m_curparam] == Param_Any)
   538 		{
   539 			m_params[m_curparam].pushedas = Param_String;
   540 		} else if (m_types[m_curparam] != Param_String) {
   541 			return SetError(SP_ERROR_PARAM);
   542 		}
   543 	} else {
   544 		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
   545 		{
   546 			return SetError(SP_ERROR_PARAMS_MAX);
   547 		}
   548 		m_params[m_curparam].pushedas = Param_String;
   549 	}
   550 
   551 	_Int_PushString((cell_t *)buffer, length, sz_flags, cp_flags);
   552 	m_curparam++;
   553 
   554 	return SP_ERROR_NONE;
   555 }
   556 
   557 void CForward::Cancel()
   558 {
   559 	if (!m_curparam)
   560 	{
   561 		return;
   562 	}
   563 
   564 	m_curparam = 0;
   565 	m_errstate = SP_ERROR_NONE;
   566 }
   567 
   568 bool CForward::AddFunction(sp_context_t *ctx, funcid_t index)
   569 {
   570 	IPlugin *pPlugin = g_PluginSys.FindPluginByContext(ctx);
   571 	if (!pPlugin)
   572 	{
   573 		return false;
   574 	}
   575 
   576 	IPluginFunction *pFunc = pPlugin->GetFunctionById(index);
   577 	if (!pFunc)
   578 	{
   579 		return false;
   580 	}
   581 
   582 	return AddFunction(pFunc);
   583 }
   584 
   585 bool CForward::RemoveFunction(IPluginFunction *func)
   586 {
   587 	bool found = false;
   588 	FuncIter iter;
   589 	IPluginFunction *pNext = NULL;
   590 
   591 	for (iter=m_functions.begin(); iter!=m_functions.end();)
   592 	{
   593 		if ((*iter) == func)
   594 		{
   595 			found = true;
   596 			/* If this iterator is being used, swap in a new one !*/
   597 			iter = m_functions.erase(iter);
   598 		} else {
   599 			iter++;
   600 		}
   601 	}
   602 
   603 	/* Cancel a call, if any */
   604 	if (found || m_curparam)
   605 	{
   606 		func->Cancel();
   607 	}
   608 
   609 	return found;
   610 }
   611 
   612 unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin)
   613 {
   614 	FuncIter iter;
   615 	IPluginFunction *func;
   616 	unsigned int removed = 0;
   617 	for (iter=m_functions.begin(); iter!=m_functions.end();)
   618 	{
   619 		func = (*iter);
   620 		if (func->GetParentPlugin() == plugin)
   621 		{
   622 			iter = m_functions.erase(iter);
   623 			removed++;
   624 		} else {
   625 			iter++;
   626 		}
   627 	}
   628 
   629 	return removed;
   630 }
   631 
   632 bool CForward::AddFunction(IPluginFunction *func)
   633 {
   634 	if (m_curparam)
   635 	{
   636 		return false;
   637 	}
   638 
   639 	//:IDEA: eventually we will tell the plugin we're using it [?]
   640 	m_functions.push_back(func);
   641 
   642 	return true;
   643 }
   644 
   645 const char *CForward::GetForwardName()
   646 {
   647 	return m_name;
   648 }
   649 
   650 unsigned int CForward::GetFunctionCount()
   651 {
   652 	return m_functions.size();
   653 }
   654 
   655 ExecType CForward::GetExecType()
   656 {
   657 	return m_ExecType;
   658 }