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
2 #include "ForwardSys.h"
6 * Gensis turns to its source, reduction occurs stepwise although the essence is all one.
7 * End of line. FTL system check.
9 * :TODO: Implement the manager. ho ho ho
11 * :TODO: WHAT NEEDS TO BE TESTED IN THIS BEAST (X=done, -=TODO)
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 = ??)
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 = ??)
29 CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int num_params, ParamType *types, va_list ap)
31 ParamType _types[SP_MAX_EXEC_PARAMS];
33 if (num_params > SP_MAX_EXEC_PARAMS)
38 if (types == NULL && num_params)
40 for (unsigned int i=0; i<num_params; i++)
42 _types[i] = va_arg(ap, ParamType);
43 if (_types[i] == Param_VarArgs && (i != num_params - 1))
50 for (unsigned int i=0; i<num_params; i++)
52 if (types[i] == Param_VarArgs && (i != num_params - 1))
59 /* First parameter can never be varargs */
60 if (types[0] == Param_VarArgs)
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 : "");
70 for (unsigned int i=0; i<num_params; i++)
72 pForward->m_types[i] = types[i];
75 if (num_params && types[num_params-1] == Param_VarArgs)
77 pForward->m_varargs = num_params--;
79 pForward->m_varargs = false;
82 pForward->m_numparams = num_params;
83 pForward->m_errstate = SP_ERROR_NONE;
88 int CForward::Execute(cell_t *result, IForwardFilter *filter)
99 filter->OnExecuteBegin();
102 FuncIter iter = m_functions.begin();
103 IPluginFunction *func;
104 cell_t cur_result = 0;
105 cell_t high_result = 0;
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];
114 /* Save local, reset */
115 memcpy(temp_info, m_params, sizeof(m_params));
118 for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
122 for (unsigned int i=0; i<num_params; i++)
124 param = &temp_info[i];
125 if (i >= m_numparams || m_types[i] == Param_Any)
127 type = param->pushedas;
131 if ((i >= m_numparams) || (type & SP_PARAMFLAG_BYREF))
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.
136 if (type == Param_String)
138 func->PushStringEx((char *)param->byref.orig_addr, param->byref.flags);
139 } else if (type == Param_Float || type == Param_Cell) {
140 func->PushCellByRef(¶m->val, 0);
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);
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);
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
155 if ((err=func->Execute(&cur_result)) != SP_ERROR_NONE)
157 bool handled = false;
160 handled = filter->OnErrorReport(this, func, err);
164 /* :TODO: invoke global error reporting here */
173 if (cur_result > high_result)
175 high_result = cur_result;
181 if (cur_result > high_result)
183 high_result = cur_result;
184 if ((ResultType)high_result == Pl_Stop)
186 iter = m_functions.end();
196 if (filter->OnFunctionReturn(this, func, &cur_result) == Pl_Stop)
198 iter = m_functions.end();
207 if (m_ExecType == ET_Event || m_ExecType == ET_Hook)
209 cur_result = high_result;
210 } else if (m_ExecType == ET_Ignore) {
214 *result = cur_result;
218 filter->OnExecuteEnd(&cur_result, success, failed);
221 return SP_ERROR_NONE;
224 int CForward::PushCell(cell_t cell)
226 if (m_curparam < m_numparams)
228 if (m_types[m_curparam] == Param_Any)
230 m_params[m_curparam].pushedas = Param_Cell;
231 } else if (m_types[m_curparam] != Param_Cell) {
232 return SetError(SP_ERROR_PARAM);
235 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
237 return SetError(SP_ERROR_PARAMS_MAX);
239 m_params[m_curparam].pushedas = Param_Cell;
242 m_params[m_curparam++].val = cell;
244 return SP_ERROR_NONE;
247 int CForward::PushFloat(float number)
249 if (m_curparam < m_numparams)
251 if (m_types[m_curparam] == Param_Any)
253 m_params[m_curparam].pushedas = Param_Float;
254 } else if (m_types[m_curparam] != Param_Float) {
255 return SetError(SP_ERROR_PARAM);
258 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
260 return SetError(SP_ERROR_PARAMS_MAX);
262 m_params[m_curparam].pushedas = Param_Float;
265 m_params[m_curparam++].val = *(cell_t *)&number;
267 return SP_ERROR_NONE;
270 int CForward::PushCellByRef(cell_t *cell, int flags)
272 if (m_curparam < m_numparams)
274 if (m_types[m_curparam] != Param_CellByRef && m_types[m_curparam] != Param_Any)
276 return SetError(SP_ERROR_PARAM);
279 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
281 return SetError(SP_ERROR_PARAMS_MAX);
285 _Int_PushArray(cell, 1, flags);
288 return SP_ERROR_NONE;
291 int CForward::PushFloatByRef(float *num, int flags)
293 if (m_curparam < m_numparams)
295 if (m_types[m_curparam] != Param_FloatByRef && m_types[m_curparam] != Param_Any)
297 return SetError(SP_ERROR_PARAM);
300 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
302 return SetError(SP_ERROR_PARAMS_MAX);
306 _Int_PushArray((cell_t *)num, 1, flags);
309 return SP_ERROR_NONE;
312 void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags)
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;
319 int CForward::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int flags)
321 /* We don't allow this here */
324 return SetError(SP_ERROR_PARAM);
327 if (m_curparam < m_numparams)
329 if (m_types[m_curparam] == Param_Any)
331 m_params[m_curparam].pushedas = Param_Array;
332 } else if (m_types[m_curparam] != Param_Array) {
333 return SetError(SP_ERROR_PARAM);
336 if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
338 return SetError(SP_ERROR_PARAMS_MAX);
340 m_params[m_curparam].pushedas = Param_Array;
348 _Int_PushArray(inarray, cells, flags);
352 return SP_ERROR_NONE;
355 int CForward::PushString(const char *string)
357 if (m_curparam < m_numparams)
359 if (m_types[m_curparam] == Param_Any)
361 m_params[m_curparam].pushedas = Param_String;
362 } else if (m_types[m_curparam] == Param_String) {
363 return SetError(SP_ERROR_PARAM);
366 if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
368 return SetError(SP_ERROR_PARAMS_MAX);
370 m_params[m_curparam].pushedas = Param_String;
373 _Int_PushArray((cell_t *)string, 0, 0);
376 return SP_ERROR_NONE;
379 int CForward::PushStringEx(char *string, int flags)
381 if (m_curparam < m_numparams)
383 if (m_types[m_curparam] == Param_Any)
385 m_params[m_curparam].pushedas = Param_String;
386 } else if (m_types[m_curparam] == Param_String) {
387 return SetError(SP_ERROR_PARAM);
390 if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
392 return SetError(SP_ERROR_PARAMS_MAX);
394 m_params[m_curparam].pushedas = Param_String;
397 _Int_PushArray((cell_t *)string, 0, flags);
400 return SP_ERROR_NONE;
403 void CForward::Cancel()
411 m_errstate = SP_ERROR_NONE;
414 bool CForward::AddFunction(sp_context_t *ctx, funcid_t index)
416 IPlugin *pPlugin = g_PluginMngr.FindPluginByContext(ctx);
422 IPluginFunction *pFunc = pPlugin->GetFunctionById(index);
428 return AddFunction(pFunc);
431 bool CForward::RemoveFunction(IPluginFunction *func)
435 IPluginFunction *pNext = NULL;
437 for (iter=m_functions.begin(); iter!=m_functions.end();)
442 /* If this iterator is being used, swap in a new one !*/
443 iter = m_functions.erase(iter);
449 /* Cancel a call, if any */
450 if (found || m_curparam)
458 unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin)
461 IPluginFunction *func;
462 unsigned int removed = 0;
463 for (iter=m_functions.begin(); iter!=m_functions.end();)
466 if (func->GetParentPlugin() == plugin)
468 iter = m_functions.erase(iter);
478 bool CForward::AddFunction(IPluginFunction *func)
485 //:TODO: eventually we will tell the plugin we're using it
486 m_functions.push_back(func);
491 const char *CForward::GetForwardName()
496 unsigned int CForward::GetFunctionCount()
498 return m_functions.size();
501 ExecType CForward::GetExecType()