2 #include "ForwardSys.h"
5 CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int num_params, ParamType *types, va_list ap)
7 ParamType _types[SP_MAX_EXEC_PARAMS];
9 if (num_params > SP_MAX_EXEC_PARAMS)
14 if (types == NULL && num_params)
16 for (unsigned int i=0; i<num_params; i++)
18 _types[i] = va_arg(ap, ParamType);
19 if (_types[i] == Param_VarArgs && (i != num_params - 1))
26 for (unsigned int i=0; i<num_params; i++)
28 if (types[i] == Param_VarArgs && (i != num_params - 1))
35 /* First parameter can never be varargs */
36 if (types[0] == Param_VarArgs)
41 CForward *pForward = new CForward;
42 pForward->m_curparam = 0;
43 pForward->m_ExecType = et;
44 snprintf(pForward->m_name, FORWARDS_NAME_MAX, "%s", name ? name : "");
46 for (unsigned int i=0; i<num_params; i++)
48 pForward->m_types[i] = types[i];
51 if (num_params && types[num_params-1] == Param_VarArgs)
53 pForward->m_varargs = true;
55 pForward->m_varargs = false;
58 pForward->m_numparams = num_params;
59 pForward->m_errstate = SP_ERROR_NONE;
60 pForward->m_CopyBacks.numrecopy = 0;
65 bool CForward::OnCopybackArray(unsigned int param,
71 /* Check if the stack is empty, this should be an assertion */
72 if (m_NextStack.empty())
74 /* This should never happen! */
75 assert(!m_NextStack.empty());
79 /* Check if we even want to copy to the next plugin */
80 if (!(flags & SMFUNC_COPYBACK_ALWAYS))
85 /* Keep track of the copy back and save the info */
86 NextCallInfo &info = m_NextStack.front();
87 info.recopy[info.numrecopy++] = param;
88 info.orig_addrs[param] = orig_addr;
89 info.sizes[param] = cells;
91 /* We don't want to override the copy. */
95 int CForward::Execute(cell_t *result, IForwardFilter *filter)
109 filter->OnExecuteBegin();
112 FuncIter iter = m_functions.begin();
113 IPluginFunction *func;
114 cell_t cur_result = 0;
115 cell_t high_result = 0;
117 unsigned int failed=0, success=0;
118 unsigned int save_numcopy = 0;
121 * Save copyback into to start the chain,
122 * then reset it for re-entrancy
124 m_NextStack.push(m_CopyBacks);
125 NextCallInfo &info = m_NextStack.front();
126 m_CopyBacks.numrecopy = 0;
128 for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
133 * Check if we need to copy a new array back into the plugin.
137 /* The last plugin has a chained copyback, we must redirect it here. */
139 cell_t *orig_addr, *targ_addr;
140 for (unsigned int i=0; i<info.numrecopy; i++)
142 /* Get the parameter info to copy */
143 param = info.recopy[i];
144 targ_addr = func->GetAddressOfPushedParam(param);
145 orig_addr = info.orig_addrs[param];
146 /* Only do the copy for valid targets */
147 if (targ_addr && orig_addr)
149 if (info.sizes[param] == 1)
151 *targ_addr = *orig_addr;
153 memcpy(targ_addr, orig_addr, info.sizes[param] * sizeof(cell_t));
156 /* If this failed, the plugin will most likely be failing as well. */
158 save_numcopy = info.numrecopy;
162 /* Call the function and deal with the return value.
163 * :TODO: only pass reader if we know we have an array in the list
165 if ((err=func->Execute(&cur_result, this)) != SP_ERROR_NONE)
167 bool handled = false;
170 handled = filter->OnErrorReport(this, func, err);
174 /* :TODO: invoke global error reporting here */
176 /* If we failed, we're not quite done. The copy chain has been broken.
177 * We have to restore it so past changes will continue to get mirrored.
179 info.numrecopy = save_numcopy;
187 if (cur_result > high_result)
189 high_result = cur_result;
195 if (cur_result > high_result)
197 high_result = cur_result;
198 if ((ResultType)high_result == Pl_Stop)
200 iter = m_functions.end();
210 if (filter->OnFunctionReturn(this, func, &cur_result) == Pl_Stop)
212 iter = m_functions.end();
223 if (m_ExecType == ET_Event || m_ExecType == ET_Hook)
225 cur_result = high_result;
226 } else if (m_ExecType == ET_Ignore) {
230 *result = cur_result;
236 filter->OnExecuteEnd(&cur_result, success, failed);
239 return SP_ERROR_NONE;
242 int CForward::PushCell(cell_t cell)
244 if (m_curparam < m_numparams)
246 if (m_types[m_curparam] != Param_Cell && m_types[m_curparam] != Param_Any)
248 return SetError(SP_ERROR_PARAM);
251 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
253 return SetError(SP_ERROR_PARAMS_MAX);
258 IPluginFunction *func;
259 for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
262 func->PushCell(cell);
267 return SP_ERROR_NONE;
270 int CForward::PushFloat(float number)
272 if (m_curparam < m_numparams)
274 if (m_types[m_curparam] != Param_Float && 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);
286 IPluginFunction *func;
287 for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
290 func->PushFloat(number);
295 return SP_ERROR_NONE;
298 int CForward::PushCellByRef(cell_t *cell, int flags)
300 if (m_curparam < m_numparams)
302 if (m_types[m_curparam] != Param_CellByRef && m_types[m_curparam] != Param_Any)
304 return SetError(SP_ERROR_PARAM);
307 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
309 return SetError(SP_ERROR_PARAMS_MAX);
313 if (flags & SMFUNC_COPYBACK_ALWAYS)
315 _Int_PushArray(cell, 1, flags);
318 IPluginFunction *func;
319 for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
322 func->PushCellByRef(cell, flags);
328 return SP_ERROR_NONE;
331 int CForward::PushFloatByRef(float *num, int flags)
333 if (m_curparam < m_numparams)
335 if (m_types[m_curparam] != Param_FloatByRef && m_types[m_curparam] != Param_Any)
337 return SetError(SP_ERROR_PARAM);
340 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
342 return SetError(SP_ERROR_PARAMS_MAX);
346 if (flags & SMFUNC_COPYBACK_ALWAYS)
348 _Int_PushArray((cell_t *)num, 1, flags);
351 IPluginFunction *func;
352 for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
355 func->PushFloatByRef(num, flags);
361 return SP_ERROR_NONE;
364 int CForward::PushCells(cell_t array[], unsigned int numcells, bool each)
368 /* Type check each cell if we need to! */
369 if (m_curparam + numcells >= m_numparams && !m_varargs)
371 return SetError(SP_ERROR_PARAMS_MAX);
373 for (unsigned int i=m_curparam; i<m_numparams; i++)
375 if (m_types[i] != Param_Any || m_types[i] != Param_Cell)
377 return SetError(SP_ERROR_PARAM);
382 if (m_curparam < m_numparams)
384 if (m_types[m_curparam] != Param_Any || m_types[m_curparam] == Param_Array)
386 return SetError(SP_ERROR_PARAM);
389 if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
391 return SetError(SP_ERROR_PARAMS_MAX);
397 IPluginFunction *func;
398 for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
401 func->PushCells(array, numcells, each);
404 m_curparam += each ? numcells : 1;
406 return SP_ERROR_NONE;
409 void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags)
412 IPluginFunction *func;
413 if (flags & SMFUNC_COPYBACK_ALWAYS)
415 /* As a special optimization, we create blank default arrays because they will be
416 * copied over anyway!
418 for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
421 func->PushArray(NULL, cells, NULL, flags);
423 m_CopyBacks.recopy[m_CopyBacks.numrecopy++] = m_curparam;
424 m_CopyBacks.orig_addrs[m_curparam] = inarray;
425 m_CopyBacks.sizes[m_curparam] = cells;
427 for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
430 func->PushArray(inarray, cells, NULL, flags);
435 int CForward::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int flags)
437 /* We don't allow this here */
440 return SetError(SP_ERROR_PARAM);
443 if (m_curparam < m_numparams)
445 if (m_types[m_curparam] != Param_Any || m_types[m_curparam] == Param_Array)
447 return SetError(SP_ERROR_PARAM);
450 if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
452 return SetError(SP_ERROR_PARAMS_MAX);
461 _Int_PushArray(inarray, cells, flags);
465 return SP_ERROR_NONE;
468 int CForward::PushString(const char *string)
470 if (m_curparam < m_numparams)
472 if (m_types[m_curparam] != Param_Any || m_types[m_curparam] == Param_String)
474 return SetError(SP_ERROR_PARAM);
477 if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
479 return SetError(SP_ERROR_PARAMS_MAX);
484 IPluginFunction *func;
485 for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
488 func->PushString(string);
493 return SP_ERROR_NONE;
496 int CForward::PushStringByRef(char *string, int flags)
498 if (m_curparam < m_numparams)
500 if (m_types[m_curparam] != Param_Any || m_types[m_curparam] == Param_String)
502 return SetError(SP_ERROR_PARAM);
505 if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
507 return SetError(SP_ERROR_PARAMS_MAX);
512 IPluginFunction *func;
513 for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
516 func->PushStringByRef(string, flags);
521 return SP_ERROR_NONE;
524 void CForward::Cancel()
532 IPluginFunction *func;
533 for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
539 m_CopyBacks.numrecopy = 0;
543 m_errstate = SP_ERROR_NONE;
546 bool CForward::AddFunction(sp_context_t *ctx, funcid_t index)
548 IPlugin *pPlugin = g_PluginMngr.FindPluginByContext(ctx);
554 IPluginFunction *pFunc = pPlugin->GetFunctionById(index);
560 return AddFunction(pFunc);
563 bool CForward::RemoveFunction(IPluginFunction *func)
567 IPluginFunction *pNext = NULL;
569 for (iter=m_functions.begin(); iter!=m_functions.end();)
574 /* If this iterator is being used, swap in a new one !*/
575 iter = m_functions.erase(iter);
582 m_AddQueue.remove(func);
584 /* Cancel a call, if any */
585 if (found && (!m_NextStack.empty() || m_curparam))
593 unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin)
596 IPluginFunction *func;
597 unsigned int removed = 0;
598 for (iter=m_functions.begin(); iter!=m_functions.end();)
601 if (func->GetParentPlugin() == plugin)
603 iter = m_functions.erase(iter);
610 for (iter=m_AddQueue.begin(); iter!=m_AddQueue.end();)
613 if (func->GetParentPlugin() == plugin)
615 /* Don't count these toward the total */
616 iter = m_functions.erase(iter);
625 void CForward::DumpAdditionQueue()
627 FuncIter iter = m_AddQueue.begin();
628 while (iter != m_AddQueue.end())
630 m_functions.push_back((*iter));
631 //:TODO: eventually we will tell the plugin we're using it
632 iter = m_AddQueue.erase(iter);
636 bool CForward::AddFunction(IPluginFunction *func)
643 if (!m_NextStack.empty())
645 m_AddQueue.push_back(func);
647 //:TODO: eventually we will tell the plugin we're using it
648 m_functions.push_back(func);
654 const char *CForward::GetForwardName()
659 unsigned int CForward::GetFunctionCount()
661 return m_functions.size();
664 ExecType CForward::GetExecType()