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