core/systems/ForwardSys.cpp
author David Anderson <dvander@alliedmods.net>
Sun Nov 12 09:51:39 2006 +0000 (2006-11-12)
changeset 183 78488edd8873
parent 181 1e1570518051
child 186 eebc5de63141
permissions -rw-r--r--
rewrote forward API to use cached parameter pushing instead of immediate pushing
removed copy back cruft since it's no longer needed
removed PushCells() from API requirements, not needed
adjusted documentation and added TODO list to ForwardSys.cpp
various internal improvements
     1 #include <assert.h>
     2 #include "ForwardSys.h"
     3 #include "PluginSys.h"
     4 
     5 /**
     6  * Gensis turns to its source, reduction occurs stepwise although the essence is all one.
     7  * End of line.  FTL system check.
     8  *
     9  * :TODO: Implement the manager.  ho ho ho
    10  *
    11  * :TODO: WHAT NEEDS TO BE TESTED IN THIS BEAST (X=done, -=TODO)
    12  * NORMAL FUNCTIONS:
    13  * X Push cells
    14  * X Push cells byref (copyback tested = yes)
    15  * - Push floats (copyback tested = ??)
    16  * - Push floats byref (copyback tested = ??)
    17  * - Push arrays  (copyback tested = ??)
    18  * - Push strings (copyback tested = ??)
    19  * VARARG FUNCTIONS:
    20  * - Pushing no varargs
    21  * - Push vararg cells (copyback should be verified to not happen = ??)
    22  * - Push vararg cells byref (copyback tested = ??)
    23  * - Push vararg floats (copyback should be verified to not happen = ??)
    24  * - Push vararg floats byref (copyback tested = ??)
    25  * - Push vararg arrays  (copyback tested = ??)
    26  * - Push vararg strings (copyback tested = ??)
    27  */
    28 
    29 CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int num_params, ParamType *types, va_list ap)
    30 {
    31 	ParamType _types[SP_MAX_EXEC_PARAMS];
    32 
    33 	if (num_params > SP_MAX_EXEC_PARAMS)
    34 	{
    35 		return NULL;
    36 	}
    37 	
    38 	if (types == NULL && num_params)
    39 	{
    40 		for (unsigned int i=0; i<num_params; i++)
    41 		{
    42 			_types[i] = va_arg(ap, ParamType);
    43 			if (_types[i] == Param_VarArgs && (i != num_params - 1))
    44 			{
    45 				return NULL;
    46 			}
    47 		}
    48 		types = _types;
    49 	} else {
    50 		for (unsigned int i=0; i<num_params; i++)
    51 		{
    52 			if (types[i] == Param_VarArgs && (i != num_params - 1))
    53 			{
    54 				return NULL;
    55 			}
    56 		}
    57 	}
    58 
    59 	/* First parameter can never be varargs */
    60 	if (types[0] == Param_VarArgs)
    61 	{
    62 		return NULL;
    63 	}
    64 
    65 	CForward *pForward = new CForward;
    66 	pForward->m_curparam = 0;
    67 	pForward->m_ExecType = et;
    68 	snprintf(pForward->m_name, FORWARDS_NAME_MAX, "%s", name ? name : "");
    69 	
    70 	for (unsigned int i=0; i<num_params; i++)
    71 	{
    72 		pForward->m_types[i] = types[i];
    73 	}
    74 
    75 	if (num_params && types[num_params-1] == Param_VarArgs)
    76 	{
    77 		pForward->m_varargs = num_params--;
    78 	} else {
    79 		pForward->m_varargs = false;
    80 	}
    81 
    82 	pForward->m_numparams = num_params;
    83 	pForward->m_errstate = SP_ERROR_NONE;
    84 
    85 	return pForward;
    86 }
    87 
    88 int CForward::Execute(cell_t *result, IForwardFilter *filter)
    89 {
    90 	if (m_errstate)
    91 	{
    92 		int err = m_errstate;
    93 		Cancel();
    94 		return err;
    95 	}
    96 
    97 	if (filter)
    98 	{
    99 		filter->OnExecuteBegin();
   100 	}
   101 
   102 	FuncIter iter = m_functions.begin();
   103 	IPluginFunction *func;
   104 	cell_t cur_result = 0;
   105 	cell_t high_result = 0;
   106 	int err;
   107 	unsigned int failed=0, success=0;
   108 	unsigned int save_numcopy = 0;
   109 	unsigned int num_params = m_curparam;
   110 	FwdParamInfo temp_info[SP_MAX_EXEC_PARAMS];
   111 	FwdParamInfo *param;
   112 	ParamType type;
   113 
   114 	/* Save local, reset */
   115 	memcpy(temp_info, m_params, sizeof(m_params));
   116 	m_curparam = 0;
   117 
   118 	for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
   119 	{
   120 		func = (*iter);
   121 
   122 		for (unsigned int i=0; i<num_params; i++)
   123 		{
   124 			param = &temp_info[i];
   125 			if (i >= m_numparams || m_types[i] == Param_Any)
   126 			{
   127 				type = param->pushedas;
   128 			} else {
   129 				type = m_types[i];
   130 			}
   131 			if ((i >= m_numparams) || (type & SP_PARAMFLAG_BYREF))
   132 			{
   133 				/* If we're byref or we're vararg, we always push everything by ref.
   134 				 * Even if they're byval, we must push them byref.
   135 				 */
   136 				if (type == Param_String) 
   137 				{
   138 					func->PushStringEx((char *)param->byref.orig_addr, param->byref.flags);
   139 				} else if (type == Param_Float || type == Param_Cell) {
   140 					func->PushCellByRef(&param->val, 0); 
   141 				} else {
   142 					func->PushArray(param->byref.orig_addr, param->byref.cells, NULL, param->byref.flags);
   143 					assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef);
   144 				}
   145 			} else {
   146 				/* If we're not byref or not vararg, our job is a bit easier. */
   147 				assert(type == Param_Cell || type == Param_Float);
   148 				func->PushCell(param->val);
   149 			}
   150 		}
   151 		
   152 		/* Call the function and deal with the return value.
   153 		 * :TODO: only pass reader if we know we have an array in the list
   154 		 */
   155 		if ((err=func->Execute(&cur_result)) != SP_ERROR_NONE)
   156 		{
   157 			bool handled = false;
   158 			if (filter)
   159 			{
   160 				handled = filter->OnErrorReport(this, func, err);
   161 			}
   162 			if (!handled)
   163 			{
   164 				/* :TODO: invoke global error reporting here */
   165 			}
   166 			failed++;
   167 		} else {
   168 			success++;
   169 			switch (m_ExecType)
   170 			{
   171 			case ET_Event:
   172 				{
   173 					if (cur_result > high_result)
   174 					{
   175 						high_result = cur_result;
   176 					}
   177 					break;
   178 				}
   179 			case ET_Hook:
   180 				{
   181 					if (cur_result > high_result)
   182 					{
   183 						high_result = cur_result;
   184 						if ((ResultType)high_result == Pl_Stop)
   185 						{
   186 							iter = m_functions.end();
   187 							break;
   188 						}
   189 					}
   190 					break;
   191 				}
   192 			case ET_Custom:
   193 				{
   194 					if (filter)
   195 					{
   196 						if (filter->OnFunctionReturn(this, func, &cur_result) == Pl_Stop)
   197 						{
   198 							iter = m_functions.end();
   199 						}
   200 					}
   201 					break;
   202 				}
   203 			}
   204 		}
   205 	}
   206 
   207 	if (m_ExecType == ET_Event || m_ExecType == ET_Hook)
   208 	{
   209 		cur_result = high_result;
   210 	} else if (m_ExecType == ET_Ignore) {
   211 		cur_result = 0;
   212 	}
   213 
   214 	*result = cur_result;
   215 
   216 	if (filter)
   217 	{
   218 		filter->OnExecuteEnd(&cur_result, success, failed);
   219 	}
   220 
   221 	return SP_ERROR_NONE;
   222 }
   223 
   224 int CForward::PushCell(cell_t cell)
   225 {
   226 	if (m_curparam < m_numparams)
   227 	{
   228 		if (m_types[m_curparam] == Param_Any)
   229 		{
   230 			m_params[m_curparam].pushedas = Param_Cell;
   231 		} else if (m_types[m_curparam] != Param_Cell) {
   232 			return SetError(SP_ERROR_PARAM);
   233 		}
   234 	} else {
   235 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   236 		{
   237 			return SetError(SP_ERROR_PARAMS_MAX);
   238 		}
   239 		m_params[m_curparam].pushedas = Param_Cell;
   240 	}
   241 
   242 	m_params[m_curparam++].val = cell;
   243 
   244 	return SP_ERROR_NONE;
   245 }
   246 
   247 int CForward::PushFloat(float number)
   248 {
   249 	if (m_curparam < m_numparams)
   250 	{
   251 		if (m_types[m_curparam] == Param_Any)
   252 		{
   253 			m_params[m_curparam].pushedas = Param_Float;
   254 		} else if (m_types[m_curparam] != Param_Float) {
   255 			return SetError(SP_ERROR_PARAM);
   256 		}
   257 	} else {
   258 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   259 		{
   260 			return SetError(SP_ERROR_PARAMS_MAX);
   261 		}
   262 		m_params[m_curparam].pushedas = Param_Float;
   263 	}
   264 
   265 	m_params[m_curparam++].val = *(cell_t *)&number;
   266 
   267 	return SP_ERROR_NONE;
   268 }
   269 
   270 int CForward::PushCellByRef(cell_t *cell, int flags)
   271 {
   272 	if (m_curparam < m_numparams)
   273 	{
   274 		if (m_types[m_curparam] != Param_CellByRef && 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 	_Int_PushArray(cell, 1, flags);
   286 	m_curparam++;
   287 
   288 	return SP_ERROR_NONE;
   289 }
   290 
   291 int CForward::PushFloatByRef(float *num, int flags)
   292 {
   293 	if (m_curparam < m_numparams)
   294 	{
   295 		if (m_types[m_curparam] != Param_FloatByRef && m_types[m_curparam] != Param_Any)
   296 		{
   297 			return SetError(SP_ERROR_PARAM);
   298 		}
   299 	} else {
   300 		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   301 		{
   302 			return SetError(SP_ERROR_PARAMS_MAX);
   303 		}
   304 	}
   305 
   306 	_Int_PushArray((cell_t *)num, 1, flags);
   307 	m_curparam++;
   308 
   309 	return SP_ERROR_NONE;
   310 }
   311 
   312 void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags)
   313 {
   314 	m_params[m_curparam].byref.cells = cells;
   315 	m_params[m_curparam].byref.flags = flags;
   316 	m_params[m_curparam].byref.orig_addr = inarray;
   317 }
   318 
   319 int CForward::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int flags)
   320 {
   321 	/* We don't allow this here */
   322 	if (!inarray)
   323 	{
   324 		return SetError(SP_ERROR_PARAM);
   325 	}
   326 
   327 	if (m_curparam < m_numparams)
   328 	{
   329 		if (m_types[m_curparam] == Param_Any)
   330 		{
   331 			m_params[m_curparam].pushedas = Param_Array;
   332 		} else if (m_types[m_curparam] != Param_Array) {
   333 			return SetError(SP_ERROR_PARAM);
   334 		}
   335 	} else {
   336 		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
   337 		{
   338 			return SetError(SP_ERROR_PARAMS_MAX);
   339 		}
   340 		m_params[m_curparam].pushedas = Param_Array;
   341 	}
   342 
   343 	if (phys_addr)
   344 	{
   345 		*phys_addr = NULL;
   346 	}
   347 
   348 	_Int_PushArray(inarray, cells, flags);
   349 
   350 	m_curparam++;
   351 
   352 	return SP_ERROR_NONE;
   353 }
   354 
   355 int CForward::PushString(const char *string)
   356 {
   357 	if (m_curparam < m_numparams)
   358 	{
   359 		if (m_types[m_curparam] == Param_Any)
   360 		{
   361 			m_params[m_curparam].pushedas = Param_String;
   362 		} else if (m_types[m_curparam] == Param_String) {
   363 			return SetError(SP_ERROR_PARAM);
   364 		}
   365 	} else {
   366 		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
   367 		{
   368 			return SetError(SP_ERROR_PARAMS_MAX);
   369 		}
   370 		m_params[m_curparam].pushedas = Param_String;
   371 	}
   372 
   373 	_Int_PushArray((cell_t *)string, 0, 0);
   374 	m_curparam++;
   375 
   376 	return SP_ERROR_NONE;
   377 }
   378 
   379 int CForward::PushStringEx(char *string, int flags)
   380 {
   381 	if (m_curparam < m_numparams)
   382 	{
   383 		if (m_types[m_curparam] == Param_Any)
   384 		{
   385 			m_params[m_curparam].pushedas = Param_String;
   386 		} else if (m_types[m_curparam] == Param_String) {
   387 			return SetError(SP_ERROR_PARAM);
   388 		}
   389 	} else {
   390 		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
   391 		{
   392 			return SetError(SP_ERROR_PARAMS_MAX);
   393 		}
   394 		m_params[m_curparam].pushedas = Param_String;
   395 	}
   396 
   397 	_Int_PushArray((cell_t *)string, 0, flags);
   398 	m_curparam++;
   399 
   400 	return SP_ERROR_NONE;
   401 }
   402 
   403 void CForward::Cancel()
   404 {
   405 	if (!m_curparam)
   406 	{
   407 		return;
   408 	}
   409 
   410 	m_curparam = 0;
   411 	m_errstate = SP_ERROR_NONE;
   412 }
   413 
   414 bool CForward::AddFunction(sp_context_t *ctx, funcid_t index)
   415 {
   416 	IPlugin *pPlugin = g_PluginMngr.FindPluginByContext(ctx);
   417 	if (!pPlugin)
   418 	{
   419 		return false;
   420 	}
   421 
   422 	IPluginFunction *pFunc = pPlugin->GetFunctionById(index);
   423 	if (!pFunc)
   424 	{
   425 		return false;
   426 	}
   427 
   428 	return AddFunction(pFunc);
   429 }
   430 
   431 bool CForward::RemoveFunction(IPluginFunction *func)
   432 {
   433 	bool found = false;
   434 	FuncIter iter;
   435 	IPluginFunction *pNext = NULL;
   436 
   437 	for (iter=m_functions.begin(); iter!=m_functions.end();)
   438 	{
   439 		if ((*iter) == func)
   440 		{
   441 			found = true;
   442 			/* If this iterator is being used, swap in a new one !*/
   443 			iter = m_functions.erase(iter);
   444 		} else {
   445 			iter++;
   446 		}
   447 	}
   448 
   449 	/* Cancel a call, if any */
   450 	if (found || m_curparam)
   451 	{
   452 		func->Cancel();
   453 	}
   454 
   455 	return found;
   456 }
   457 
   458 unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin)
   459 {
   460 	FuncIter iter;
   461 	IPluginFunction *func;
   462 	unsigned int removed = 0;
   463 	for (iter=m_functions.begin(); iter!=m_functions.end();)
   464 	{
   465 		func = (*iter);
   466 		if (func->GetParentPlugin() == plugin)
   467 		{
   468 			iter = m_functions.erase(iter);
   469 			removed++;
   470 		} else {
   471 			iter++;
   472 		}
   473 	}
   474 
   475 	return removed;
   476 }
   477 
   478 bool CForward::AddFunction(IPluginFunction *func)
   479 {
   480 	if (m_curparam)
   481 	{
   482 		return false;
   483 	}
   484 
   485 	//:TODO: eventually we will tell the plugin we're using it
   486 	m_functions.push_back(func);
   487 
   488 	return true;
   489 }
   490 
   491 const char *CForward::GetForwardName()
   492 {
   493 	return m_name;
   494 }
   495 
   496 unsigned int CForward::GetFunctionCount()
   497 {
   498 	return m_functions.size();
   499 }
   500 
   501 ExecType CForward::GetExecType()
   502 {
   503 	return m_ExecType;
   504 }