dvander@180: #include dvander@180: #include "ForwardSys.h" dvander@180: #include "PluginSys.h" dvander@180: dvander@180: CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int num_params, ParamType *types, va_list ap) dvander@180: { dvander@180: ParamType _types[SP_MAX_EXEC_PARAMS]; dvander@180: dvander@180: if (num_params > SP_MAX_EXEC_PARAMS) dvander@180: { dvander@180: return NULL; dvander@180: } dvander@180: dvander@180: if (types == NULL && num_params) dvander@180: { dvander@180: for (unsigned int i=0; im_curparam = 0; dvander@180: pForward->m_ExecType = et; dvander@180: snprintf(pForward->m_name, FORWARDS_NAME_MAX, "%s", name ? name : ""); dvander@180: dvander@180: for (unsigned int i=0; im_types[i] = types[i]; dvander@180: } dvander@180: dvander@180: if (num_params && types[num_params-1] == Param_VarArgs) dvander@180: { dvander@180: pForward->m_varargs = true; dvander@180: } else { dvander@180: pForward->m_varargs = false; dvander@180: } dvander@180: dvander@180: pForward->m_numparams = num_params; dvander@180: pForward->m_errstate = SP_ERROR_NONE; dvander@180: pForward->m_CopyBacks.numrecopy = 0; dvander@180: dvander@180: return pForward; dvander@180: } dvander@180: dvander@180: bool CForward::OnCopybackArray(unsigned int param, dvander@180: unsigned int cells, dvander@180: cell_t *source_addr, dvander@180: cell_t *orig_addr, dvander@180: int flags) dvander@180: { dvander@180: /* Check if the stack is empty, this should be an assertion */ dvander@180: if (m_NextStack.empty()) dvander@180: { dvander@180: /* This should never happen! */ dvander@180: assert(!m_NextStack.empty()); dvander@180: return true; dvander@180: } dvander@180: dvander@180: /* Check if we even want to copy to the next plugin */ dvander@180: if (!(flags & SMFUNC_COPYBACK_ALWAYS)) dvander@180: { dvander@180: return true; dvander@180: } dvander@180: dvander@180: /* Keep track of the copy back and save the info */ dvander@180: NextCallInfo &info = m_NextStack.front(); dvander@180: info.recopy[info.numrecopy++] = param; dvander@180: info.orig_addrs[param] = orig_addr; dvander@180: info.sizes[param] = cells; dvander@180: dvander@180: /* We don't want to override the copy. */ dvander@180: return true; dvander@180: } dvander@180: dvander@180: int CForward::Execute(cell_t *result, IForwardFilter *filter) dvander@180: { dvander@180: if (m_errstate) dvander@180: { dvander@180: int err = m_errstate; dvander@180: Cancel(); dvander@180: return err; dvander@180: } dvander@180: dvander@180: /* Reset marker */ dvander@180: m_curparam = 0; dvander@180: dvander@180: if (filter) dvander@180: { dvander@180: filter->OnExecuteBegin(); dvander@180: } dvander@180: dvander@180: FuncIter iter = m_functions.begin(); dvander@180: IPluginFunction *func; dvander@180: cell_t cur_result = 0; dvander@180: cell_t high_result = 0; dvander@180: int err; dvander@180: unsigned int failed=0, success=0; dvander@180: unsigned int save_numcopy = 0; dvander@180: dvander@180: /** dvander@180: * Save copyback into to start the chain, dvander@180: * then reset it for re-entrancy dvander@180: */ dvander@180: m_NextStack.push(m_CopyBacks); dvander@180: NextCallInfo &info = m_NextStack.front(); dvander@180: m_CopyBacks.numrecopy = 0; dvander@180: dvander@180: for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) dvander@180: { dvander@180: func = (*iter); dvander@180: dvander@180: /** dvander@180: * Check if we need to copy a new array back into the plugin. dvander@180: */ dvander@180: if (info.numrecopy) dvander@180: { dvander@180: /* The last plugin has a chained copyback, we must redirect it here. */ dvander@180: unsigned int param; dvander@180: cell_t *orig_addr, *targ_addr; dvander@180: for (unsigned int i=0; iGetAddressOfPushedParam(param); dvander@180: orig_addr = info.orig_addrs[param]; dvander@180: /* Only do the copy for valid targets */ dvander@180: if (targ_addr && orig_addr) dvander@180: { dvander@180: if (info.sizes[param] == 1) dvander@180: { dvander@180: *targ_addr = *orig_addr; dvander@180: } else { dvander@180: memcpy(targ_addr, orig_addr, info.sizes[param] * sizeof(cell_t)); dvander@180: } dvander@180: } dvander@180: /* If this failed, the plugin will most likely be failing as well. */ dvander@180: } dvander@180: save_numcopy = info.numrecopy; dvander@180: info.numrecopy = 0; dvander@180: } dvander@180: dvander@180: /* Call the function and deal with the return value. dvander@180: * :TODO: only pass reader if we know we have an array in the list dvander@180: */ dvander@180: if ((err=func->Execute(&cur_result, this)) != SP_ERROR_NONE) dvander@180: { dvander@180: bool handled = false; dvander@180: if (filter) dvander@180: { dvander@180: handled = filter->OnErrorReport(this, func, err); dvander@180: } dvander@180: if (!handled) dvander@180: { dvander@180: /* :TODO: invoke global error reporting here */ dvander@180: } dvander@180: /* If we failed, we're not quite done. The copy chain has been broken. dvander@180: * We have to restore it so past changes will continue to get mirrored. dvander@180: */ dvander@180: info.numrecopy = save_numcopy; dvander@180: failed++; dvander@180: } else { dvander@180: success++; dvander@180: switch (m_ExecType) dvander@180: { dvander@180: case ET_Event: dvander@180: { dvander@180: if (cur_result > high_result) dvander@180: { dvander@180: high_result = cur_result; dvander@180: } dvander@180: break; dvander@180: } dvander@180: case ET_Hook: dvander@180: { dvander@180: if (cur_result > high_result) dvander@180: { dvander@180: high_result = cur_result; dvander@180: if ((ResultType)high_result == Pl_Stop) dvander@180: { dvander@180: iter = m_functions.end(); dvander@180: break; dvander@180: } dvander@180: } dvander@180: break; dvander@180: } dvander@180: case ET_Custom: dvander@180: { dvander@180: if (filter) dvander@180: { dvander@180: if (filter->OnFunctionReturn(this, func, &cur_result) == Pl_Stop) dvander@180: { dvander@180: iter = m_functions.end(); dvander@180: } dvander@180: } dvander@180: break; dvander@180: } dvander@180: } dvander@180: } dvander@180: } dvander@180: dvander@180: m_NextStack.pop(); dvander@180: dvander@180: if (m_ExecType == ET_Event || m_ExecType == ET_Hook) dvander@180: { dvander@180: cur_result = high_result; dvander@180: } else if (m_ExecType == ET_Ignore) { dvander@180: cur_result = 0; dvander@180: } dvander@180: dvander@180: *result = cur_result; dvander@180: dvander@180: DumpAdditionQueue(); dvander@180: dvander@180: if (filter) dvander@180: { dvander@180: filter->OnExecuteEnd(&cur_result, success, failed); dvander@180: } dvander@180: dvander@180: return SP_ERROR_NONE; dvander@180: } dvander@180: dvander@180: int CForward::PushCell(cell_t cell) dvander@180: { dvander@180: if (m_curparam < m_numparams) dvander@180: { dvander@180: if (m_types[m_curparam] != Param_Cell && m_types[m_curparam] != Param_Any) dvander@180: { dvander@180: return SetError(SP_ERROR_PARAM); dvander@180: } dvander@180: } else { dvander@180: if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS) dvander@180: { dvander@180: return SetError(SP_ERROR_PARAMS_MAX); dvander@180: } dvander@180: } dvander@180: dvander@180: FuncIter iter; dvander@180: IPluginFunction *func; dvander@180: for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) dvander@180: { dvander@180: func = (*iter); dvander@180: func->PushCell(cell); dvander@180: } dvander@180: dvander@180: m_curparam++; dvander@180: dvander@180: return SP_ERROR_NONE; dvander@180: } dvander@180: dvander@180: int CForward::PushFloat(float number) dvander@180: { dvander@180: if (m_curparam < m_numparams) dvander@180: { dvander@180: if (m_types[m_curparam] != Param_Float && m_types[m_curparam] != Param_Any) dvander@180: { dvander@180: return SetError(SP_ERROR_PARAM); dvander@180: } dvander@180: } else { dvander@180: if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS) dvander@180: { dvander@180: return SetError(SP_ERROR_PARAMS_MAX); dvander@180: } dvander@180: } dvander@180: dvander@180: FuncIter iter; dvander@180: IPluginFunction *func; dvander@180: for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) dvander@180: { dvander@180: func = (*iter); dvander@180: func->PushFloat(number); dvander@180: } dvander@180: dvander@180: m_curparam++; dvander@180: dvander@180: return SP_ERROR_NONE; dvander@180: } dvander@180: dvander@180: int CForward::PushCellByRef(cell_t *cell, int flags) dvander@180: { dvander@180: if (m_curparam < m_numparams) dvander@180: { dvander@180: if (m_types[m_curparam] != Param_CellByRef && m_types[m_curparam] != Param_Any) dvander@180: { dvander@180: return SetError(SP_ERROR_PARAM); dvander@180: } dvander@180: } else { dvander@180: if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS) dvander@180: { dvander@180: return SetError(SP_ERROR_PARAMS_MAX); dvander@180: } dvander@180: } dvander@180: dvander@180: if (flags & SMFUNC_COPYBACK_ALWAYS) dvander@180: { dvander@180: _Int_PushArray(cell, 1, flags); dvander@180: } else { dvander@180: FuncIter iter; dvander@180: IPluginFunction *func; dvander@180: for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) dvander@180: { dvander@180: func = (*iter); dvander@180: func->PushCellByRef(cell, flags); dvander@180: } dvander@180: } dvander@180: dvander@180: m_curparam++; dvander@180: dvander@180: return SP_ERROR_NONE; dvander@180: } dvander@180: dvander@180: int CForward::PushFloatByRef(float *num, int flags) dvander@180: { dvander@180: if (m_curparam < m_numparams) dvander@180: { dvander@180: if (m_types[m_curparam] != Param_FloatByRef && m_types[m_curparam] != Param_Any) dvander@180: { dvander@180: return SetError(SP_ERROR_PARAM); dvander@180: } dvander@180: } else { dvander@180: if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS) dvander@180: { dvander@180: return SetError(SP_ERROR_PARAMS_MAX); dvander@180: } dvander@180: } dvander@180: dvander@180: if (flags & SMFUNC_COPYBACK_ALWAYS) dvander@180: { dvander@180: _Int_PushArray((cell_t *)num, 1, flags); dvander@180: } else { dvander@180: FuncIter iter; dvander@180: IPluginFunction *func; dvander@180: for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) dvander@180: { dvander@180: func = (*iter); dvander@180: func->PushFloatByRef(num, flags); dvander@180: } dvander@180: } dvander@180: dvander@180: m_curparam++; dvander@180: dvander@180: return SP_ERROR_NONE; dvander@180: } dvander@180: dvander@180: int CForward::PushCells(cell_t array[], unsigned int numcells, bool each) dvander@180: { dvander@180: if (each) dvander@180: { dvander@180: /* Type check each cell if we need to! */ dvander@180: if (m_curparam + numcells >= m_numparams && !m_varargs) dvander@180: { dvander@180: return SetError(SP_ERROR_PARAMS_MAX); dvander@180: } else { dvander@180: for (unsigned int i=m_curparam; i SP_MAX_EXEC_PARAMS) dvander@180: { dvander@180: return SetError(SP_ERROR_PARAMS_MAX); dvander@180: } dvander@180: } dvander@180: } dvander@180: dvander@180: FuncIter iter; dvander@180: IPluginFunction *func; dvander@180: for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) dvander@180: { dvander@180: func = (*iter); dvander@180: func->PushCells(array, numcells, each); dvander@180: } dvander@180: dvander@180: m_curparam += each ? numcells : 1; dvander@180: dvander@180: return SP_ERROR_NONE; dvander@180: } dvander@180: dvander@180: void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags) dvander@180: { dvander@180: FuncIter iter; dvander@180: IPluginFunction *func; dvander@180: if (flags & SMFUNC_COPYBACK_ALWAYS) dvander@180: { dvander@180: /* As a special optimization, we create blank default arrays because they will be dvander@180: * copied over anyway! dvander@180: */ dvander@180: for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) dvander@180: { dvander@180: func = (*iter); dvander@180: func->PushArray(NULL, cells, NULL, flags); dvander@180: } dvander@180: m_CopyBacks.recopy[m_CopyBacks.numrecopy++] = m_curparam; dvander@180: m_CopyBacks.orig_addrs[m_curparam] = inarray; dvander@180: m_CopyBacks.sizes[m_curparam] = cells; dvander@180: } else { dvander@180: for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) dvander@180: { dvander@180: func = (*iter); dvander@180: func->PushArray(inarray, cells, NULL, flags); dvander@180: } dvander@180: } dvander@180: } dvander@180: dvander@180: int CForward::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int flags) dvander@180: { dvander@180: /* We don't allow this here */ dvander@180: if (!inarray) dvander@180: { dvander@180: return SetError(SP_ERROR_PARAM); dvander@180: } dvander@180: dvander@180: if (m_curparam < m_numparams) dvander@180: { dvander@180: if (m_types[m_curparam] != Param_Any || m_types[m_curparam] == Param_Array) dvander@180: { dvander@180: return SetError(SP_ERROR_PARAM); dvander@180: } dvander@180: } else { dvander@180: if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS) dvander@180: { dvander@180: return SetError(SP_ERROR_PARAMS_MAX); dvander@180: } dvander@180: } dvander@180: dvander@180: if (phys_addr) dvander@180: { dvander@180: *phys_addr = NULL; dvander@180: } dvander@180: dvander@180: _Int_PushArray(inarray, cells, flags); dvander@180: dvander@180: m_curparam++; dvander@180: dvander@180: return SP_ERROR_NONE; dvander@180: } dvander@180: dvander@180: int CForward::PushString(const char *string) dvander@180: { dvander@180: if (m_curparam < m_numparams) dvander@180: { dvander@180: if (m_types[m_curparam] != Param_Any || m_types[m_curparam] == Param_String) dvander@180: { dvander@180: return SetError(SP_ERROR_PARAM); dvander@180: } dvander@180: } else { dvander@180: if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS) dvander@180: { dvander@180: return SetError(SP_ERROR_PARAMS_MAX); dvander@180: } dvander@180: } dvander@180: dvander@180: FuncIter iter; dvander@180: IPluginFunction *func; dvander@180: for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) dvander@180: { dvander@180: func = (*iter); dvander@180: func->PushString(string); dvander@180: } dvander@180: dvander@180: m_curparam++; dvander@180: dvander@180: return SP_ERROR_NONE; dvander@180: } dvander@180: dvander@180: int CForward::PushStringByRef(char *string, int flags) dvander@180: { dvander@180: if (m_curparam < m_numparams) dvander@180: { dvander@180: if (m_types[m_curparam] != Param_Any || m_types[m_curparam] == Param_String) dvander@180: { dvander@180: return SetError(SP_ERROR_PARAM); dvander@180: } dvander@180: } else { dvander@180: if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS) dvander@180: { dvander@180: return SetError(SP_ERROR_PARAMS_MAX); dvander@180: } dvander@180: } dvander@180: dvander@180: FuncIter iter; dvander@180: IPluginFunction *func; dvander@180: for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) dvander@180: { dvander@180: func = (*iter); dvander@180: func->PushStringByRef(string, flags); dvander@180: } dvander@180: dvander@180: m_curparam++; dvander@180: dvander@180: return SP_ERROR_NONE; dvander@180: } dvander@180: dvander@180: void CForward::Cancel() dvander@180: { dvander@180: if (!m_curparam) dvander@180: { dvander@180: return; dvander@180: } dvander@180: dvander@180: FuncIter iter; dvander@180: IPluginFunction *func; dvander@180: for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) dvander@180: { dvander@180: func = (*iter); dvander@180: func->Cancel(); dvander@180: } dvander@180: dvander@180: m_CopyBacks.numrecopy = 0; dvander@180: dvander@180: DumpAdditionQueue(); dvander@180: dvander@180: m_errstate = SP_ERROR_NONE; dvander@180: } dvander@180: dvander@180: bool CForward::AddFunction(sp_context_t *ctx, funcid_t index) dvander@180: { dvander@180: IPlugin *pPlugin = g_PluginMngr.FindPluginByContext(ctx); dvander@180: if (!pPlugin) dvander@180: { dvander@180: return false; dvander@180: } dvander@180: dvander@180: IPluginFunction *pFunc = pPlugin->GetFunctionById(index); dvander@180: if (!pFunc) dvander@180: { dvander@180: return false; dvander@180: } dvander@180: dvander@180: return AddFunction(pFunc); dvander@180: } dvander@180: dvander@180: bool CForward::RemoveFunction(IPluginFunction *func) dvander@180: { dvander@180: bool found = false; dvander@180: FuncIter iter; dvander@180: IPluginFunction *pNext = NULL; dvander@180: dvander@180: for (iter=m_functions.begin(); iter!=m_functions.end();) dvander@180: { dvander@180: if ((*iter) == func) dvander@180: { dvander@180: found = true; dvander@180: /* If this iterator is being used, swap in a new one !*/ dvander@180: iter = m_functions.erase(iter); dvander@180: } else { dvander@180: iter++; dvander@180: } dvander@180: } dvander@180: dvander@180: /* Just in case */ dvander@180: m_AddQueue.remove(func); dvander@180: dvander@180: /* Cancel a call, if any */ dvander@180: if (found && (!m_NextStack.empty() || m_curparam)) dvander@180: { dvander@180: func->Cancel(); dvander@180: } dvander@180: dvander@180: return found; dvander@180: } dvander@180: dvander@180: unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin) dvander@180: { dvander@180: FuncIter iter; dvander@180: IPluginFunction *func; dvander@180: unsigned int removed = 0; dvander@180: for (iter=m_functions.begin(); iter!=m_functions.end();) dvander@180: { dvander@180: func = (*iter); dvander@180: if (func->GetParentPlugin() == plugin) dvander@180: { dvander@180: iter = m_functions.erase(iter); dvander@180: removed++; dvander@180: } else { dvander@180: iter++; dvander@180: } dvander@180: } dvander@180: dvander@180: for (iter=m_AddQueue.begin(); iter!=m_AddQueue.end();) dvander@180: { dvander@180: func = (*iter); dvander@180: if (func->GetParentPlugin() == plugin) dvander@180: { dvander@180: /* Don't count these toward the total */ dvander@180: iter = m_functions.erase(iter); dvander@180: } else { dvander@180: iter++; dvander@180: } dvander@180: } dvander@180: dvander@180: return removed; dvander@180: } dvander@180: dvander@180: void CForward::DumpAdditionQueue() dvander@180: { dvander@180: FuncIter iter = m_AddQueue.begin(); dvander@180: while (iter != m_AddQueue.end()) dvander@180: { dvander@180: m_functions.push_back((*iter)); dvander@180: //:TODO: eventually we will tell the plugin we're using it dvander@180: iter = m_AddQueue.erase(iter); dvander@180: } dvander@180: } dvander@180: dvander@180: bool CForward::AddFunction(IPluginFunction *func) dvander@180: { dvander@180: if (m_curparam) dvander@180: { dvander@180: return false; dvander@180: } dvander@180: dvander@180: if (!m_NextStack.empty()) dvander@180: { dvander@180: m_AddQueue.push_back(func); dvander@180: } else { dvander@180: //:TODO: eventually we will tell the plugin we're using it dvander@180: m_functions.push_back(func); dvander@180: } dvander@180: dvander@180: return true; dvander@180: } dvander@180: dvander@180: const char *CForward::GetForwardName() dvander@180: { dvander@180: return m_name; dvander@180: } dvander@180: dvander@180: unsigned int CForward::GetFunctionCount() dvander@180: { dvander@180: return m_functions.size(); dvander@180: } dvander@180: dvander@180: ExecType CForward::GetExecType() dvander@180: { dvander@180: return m_ExecType; dvander@180: }