2 #include "ForwardSys.h"
5 CForwardManager g_Forwards;
8 * Gensis turns to its source, reduction occurs stepwise although the essence is all one.
9 * End of line. FTL system check.
11 * :TODO: WHAT NEEDS TO BE TESTED IN THIS BEAST
13 * - Pushing no varargs
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!
19 void CForwardManager::OnSourceModAllInitialized()
21 g_PluginSys.AddPluginsListener(this);
24 void CForwardManager::OnSourceModShutdown()
26 g_PluginSys.RemovePluginsListener(this);
29 IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned int num_params, ParamType *types, ...)
35 fwd = CForward::CreateForward(name, et, num_params, types, ap);
41 m_managed.push_back(fwd);
47 IChangeableForward *CForwardManager::CreateForwardEx(const char *name, ExecType et, int num_params, ParamType *types, ...)
53 fwd = CForward::CreateForward(name, et, num_params, types, ap);
59 m_unmanaged.push_back(fwd);
65 void CForwardManager::OnPluginLoaded(IPlugin *plugin)
67 /* Attach any globally managed forwards */
68 List<CForward *>::iterator iter;
71 for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
74 IPluginFunction *pFunc = plugin->GetFunctionByName(fwd->GetForwardName());
77 fwd->AddFunction(pFunc);
82 void CForwardManager::OnPluginUnloaded(IPlugin *plugin)
84 List<CForward *>::iterator iter;
87 for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
90 fwd->RemoveFunctionsOfPlugin(plugin);
93 for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
96 fwd->RemoveFunctionsOfPlugin(plugin);
100 IForward *CForwardManager::FindForward(const char *name, IChangeableForward **ifchng)
102 List<CForward *>::iterator iter;
105 for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
108 if (strcmp(fwd->GetForwardName(), name) == 0)
118 for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
121 if (strcmp(fwd->GetForwardName(), name) == 0)
139 void CForwardManager::ReleaseForward(IForward *forward)
141 ForwardFree(static_cast<CForward *>(forward));
144 void CForwardManager::ForwardFree(CForward *fwd)
146 m_FreeForwards.push(fwd);
149 CForward *CForwardManager::ForwardMake()
152 if (m_FreeForwards.empty())
156 fwd = m_FreeForwards.front();
157 m_FreeForwards.pop();
162 /*************************************
163 * ACTUAL FORWARD API IMPLEMENTATION *
164 *************************************/
166 CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int num_params, ParamType *types, va_list ap)
168 ParamType _types[SP_MAX_EXEC_PARAMS];
170 if (num_params > SP_MAX_EXEC_PARAMS)
175 if (types == NULL && num_params)
177 for (unsigned int i=0; i<num_params; i++)
179 _types[i] = va_arg(ap, ParamType);
180 if (_types[i] == Param_VarArgs && (i != num_params - 1))
187 for (unsigned int i=0; i<num_params; i++)
189 if (types[i] == Param_VarArgs && (i != num_params - 1))
196 /* First parameter can never be varargs */
197 if (types[0] == Param_VarArgs)
202 CForward *pForward = g_Forwards.ForwardMake();
203 pForward->m_curparam = 0;
204 pForward->m_ExecType = et;
205 snprintf(pForward->m_name, FORWARDS_NAME_MAX, "%s", name ? name : "");
207 for (unsigned int i=0; i<num_params; i++)
209 pForward->m_types[i] = types[i];
212 if (num_params && types[num_params-1] == Param_VarArgs)
214 pForward->m_varargs = num_params--;
216 pForward->m_varargs = false;
219 pForward->m_numparams = num_params;
220 pForward->m_errstate = SP_ERROR_NONE;
225 int CForward::Execute(cell_t *result, IForwardFilter *filter)
229 int err = m_errstate;
236 filter->OnExecuteBegin();
239 FuncIter iter = m_functions.begin();
240 IPluginFunction *func;
241 cell_t cur_result = 0;
242 cell_t high_result = 0;
244 unsigned int failed=0, success=0;
245 unsigned int save_numcopy = 0;
246 unsigned int num_params = m_curparam;
247 FwdParamInfo temp_info[SP_MAX_EXEC_PARAMS];
251 /* Save local, reset */
252 memcpy(temp_info, m_params, sizeof(m_params));
255 for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
259 for (unsigned int i=0; i<num_params; i++)
261 param = &temp_info[i];
262 if (i >= m_numparams || m_types[i] == Param_Any)
264 type = param->pushedas;
268 if ((i >= m_numparams) || (type & SP_PARAMFLAG_BYREF))
270 /* If we're byref or we're vararg, we always push everything by ref.
271 * Even if they're byval, we must push them byref.
273 if (type == Param_String)
275 func->PushStringEx((char *)param->byref.orig_addr, param->byref.cells, param->byref.sz_flags, param->byref.flags);
276 } else if (type == Param_Float || type == Param_Cell) {
277 func->PushCellByRef(¶m->val, 0);
279 func->PushArray(param->byref.orig_addr, param->byref.cells, NULL, param->byref.flags);
280 assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef);
283 /* If we're not byref or not vararg, our job is a bit easier. */
284 assert(type == Param_Cell || type == Param_Float);
285 func->PushCell(param->val);
289 /* Call the function and deal with the return value. */
290 if ((err=func->Execute(&cur_result)) != SP_ERROR_NONE)
292 bool handled = false;
295 handled = filter->OnErrorReport(this, func, err);
299 /* :TODO: invoke global error reporting here */
308 if (cur_result > high_result)
310 high_result = cur_result;
316 if (cur_result > high_result)
318 high_result = cur_result;
319 if ((ResultType)high_result == Pl_Stop)
321 iter = m_functions.end();
331 if (filter->OnFunctionReturn(this, func, &cur_result) == Pl_Stop)
333 iter = m_functions.end();
342 if (m_ExecType == ET_Event || m_ExecType == ET_Hook)
344 cur_result = high_result;
345 } else if (m_ExecType == ET_Ignore) {
349 *result = cur_result;
353 filter->OnExecuteEnd(&cur_result, success, failed);
356 return SP_ERROR_NONE;
359 int CForward::PushCell(cell_t cell)
361 if (m_curparam < m_numparams)
363 if (m_types[m_curparam] == Param_Any)
365 m_params[m_curparam].pushedas = Param_Cell;
366 } else if (m_types[m_curparam] != Param_Cell) {
367 return SetError(SP_ERROR_PARAM);
370 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
372 return SetError(SP_ERROR_PARAMS_MAX);
374 m_params[m_curparam].pushedas = Param_Cell;
377 m_params[m_curparam++].val = cell;
379 return SP_ERROR_NONE;
382 int CForward::PushFloat(float number)
384 if (m_curparam < m_numparams)
386 if (m_types[m_curparam] == Param_Any)
388 m_params[m_curparam].pushedas = Param_Float;
389 } else if (m_types[m_curparam] != Param_Float) {
390 return SetError(SP_ERROR_PARAM);
393 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
395 return SetError(SP_ERROR_PARAMS_MAX);
397 m_params[m_curparam].pushedas = Param_Float;
400 m_params[m_curparam++].val = *(cell_t *)&number;
402 return SP_ERROR_NONE;
405 int CForward::PushCellByRef(cell_t *cell, int flags)
407 if (m_curparam < m_numparams)
409 if (m_types[m_curparam] == Param_Any)
411 m_params[m_curparam].pushedas = Param_CellByRef;
412 } else if (m_types[m_curparam] != Param_CellByRef) {
413 return SetError(SP_ERROR_PARAM);
416 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
418 return SetError(SP_ERROR_PARAMS_MAX);
420 m_params[m_curparam].pushedas = Param_CellByRef;
423 _Int_PushArray(cell, 1, flags);
426 return SP_ERROR_NONE;
429 int CForward::PushFloatByRef(float *num, int flags)
431 if (m_curparam < m_numparams)
433 if (m_types[m_curparam] == Param_Any)
435 m_params[m_curparam].pushedas = Param_FloatByRef;
436 } else if (m_types[m_curparam] != Param_FloatByRef) {
437 return SetError(SP_ERROR_PARAM);
440 if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
442 return SetError(SP_ERROR_PARAMS_MAX);
444 m_params[m_curparam].pushedas = Param_FloatByRef;
447 _Int_PushArray((cell_t *)num, 1, flags);
450 return SP_ERROR_NONE;
453 void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags)
455 m_params[m_curparam].byref.cells = cells;
456 m_params[m_curparam].byref.flags = flags;
457 m_params[m_curparam].byref.orig_addr = inarray;
460 int CForward::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int flags)
462 /* We don't allow this here */
465 return SetError(SP_ERROR_PARAM);
468 if (m_curparam < m_numparams)
470 if (m_types[m_curparam] == Param_Any)
472 m_params[m_curparam].pushedas = Param_Array;
473 } else if (m_types[m_curparam] != Param_Array) {
474 return SetError(SP_ERROR_PARAM);
477 if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
479 return SetError(SP_ERROR_PARAMS_MAX);
481 m_params[m_curparam].pushedas = Param_Array;
489 _Int_PushArray(inarray, cells, flags);
493 return SP_ERROR_NONE;
496 void CForward::_Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_flags)
498 m_params[m_curparam].byref.cells = cells; /* Notice this contains the char count not cell count */
499 m_params[m_curparam].byref.flags = cp_flags;
500 m_params[m_curparam].byref.orig_addr = inarray;
501 m_params[m_curparam].byref.sz_flags = sz_flags;
504 int CForward::PushString(const char *string)
506 if (m_curparam < m_numparams)
508 if (m_types[m_curparam] == Param_Any)
510 m_params[m_curparam].pushedas = Param_String;
511 } else if (m_types[m_curparam] != Param_String) {
512 return SetError(SP_ERROR_PARAM);
515 if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
517 return SetError(SP_ERROR_PARAMS_MAX);
519 m_params[m_curparam].pushedas = Param_String;
522 _Int_PushString((cell_t *)string, strlen(string)+1, SM_PARAM_STRING_COPY, 0);
525 return SP_ERROR_NONE;
528 int CForward::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
530 if (m_curparam < m_numparams)
532 if (m_types[m_curparam] == Param_Any)
534 m_params[m_curparam].pushedas = Param_String;
535 } else if (m_types[m_curparam] != Param_String) {
536 return SetError(SP_ERROR_PARAM);
539 if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
541 return SetError(SP_ERROR_PARAMS_MAX);
543 m_params[m_curparam].pushedas = Param_String;
546 _Int_PushString((cell_t *)buffer, length, sz_flags, cp_flags);
549 return SP_ERROR_NONE;
552 void CForward::Cancel()
560 m_errstate = SP_ERROR_NONE;
563 bool CForward::AddFunction(sp_context_t *ctx, funcid_t index)
565 IPlugin *pPlugin = g_PluginSys.FindPluginByContext(ctx);
571 IPluginFunction *pFunc = pPlugin->GetFunctionById(index);
577 return AddFunction(pFunc);
580 bool CForward::RemoveFunction(IPluginFunction *func)
584 IPluginFunction *pNext = NULL;
586 for (iter=m_functions.begin(); iter!=m_functions.end();)
591 /* If this iterator is being used, swap in a new one !*/
592 iter = m_functions.erase(iter);
598 /* Cancel a call, if any */
599 if (found || m_curparam)
607 unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin)
610 IPluginFunction *func;
611 unsigned int removed = 0;
612 for (iter=m_functions.begin(); iter!=m_functions.end();)
615 if (func->GetParentPlugin() == plugin)
617 iter = m_functions.erase(iter);
627 bool CForward::AddFunction(IPluginFunction *func)
634 //:IDEA: eventually we will tell the plugin we're using it [?]
635 m_functions.push_back(func);
640 const char *CForward::GetForwardName()
645 unsigned int CForward::GetFunctionCount()
647 return m_functions.size();
650 ExecType CForward::GetExecType()