Extend function calling API for natives and allow catching exceptions.
Change sourcepawn url.
This commit is contained in:
		
							parent
							
								
									8ac0c18674
								
							
						
					
					
						commit
						11d12aad11
					
				
							
								
								
									
										2
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							| @ -3,4 +3,4 @@ | |||||||
| 	url = https://github.com/alliedmodders/amtl | 	url = https://github.com/alliedmodders/amtl | ||||||
| [submodule "sourcepawn"] | [submodule "sourcepawn"] | ||||||
| 	path = sourcepawn | 	path = sourcepawn | ||||||
| 	url = https://github.com/alliedmodders/sourcepawn | 	url = https://github.com/BotoX/sourcepawn.git | ||||||
|  | |||||||
| @ -85,6 +85,7 @@ for arch in SM.archs: | |||||||
|     'smn_halflife.cpp', |     'smn_halflife.cpp', | ||||||
|     'FrameIterator.cpp', |     'FrameIterator.cpp', | ||||||
|     'DatabaseConfBuilder.cpp', |     'DatabaseConfBuilder.cpp', | ||||||
|  |     'NativeInvoker.cpp', | ||||||
|   ] |   ] | ||||||
| 
 | 
 | ||||||
|   if arch == 'x64': |   if arch == 'x64': | ||||||
|  | |||||||
							
								
								
									
										321
									
								
								core/logic/NativeInvoker.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										321
									
								
								core/logic/NativeInvoker.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,321 @@ | |||||||
|  | // vim: set sts=2 ts=8 sw=2 tw=99 et:
 | ||||||
|  | //
 | ||||||
|  | // Copyright (C) 2006-2015 AlliedModders LLC
 | ||||||
|  | //
 | ||||||
|  | // This file is part of SourcePawn. SourcePawn is free software: you can
 | ||||||
|  | // redistribute it and/or modify it under the terms of the GNU General Public
 | ||||||
|  | // License as published by the Free Software Foundation, either version 3 of
 | ||||||
|  | // the License, or (at your option) any later version.
 | ||||||
|  | //
 | ||||||
|  | // You should have received a copy of the GNU General Public License along with
 | ||||||
|  | // SourcePawn. If not, see http://www.gnu.org/licenses/.
 | ||||||
|  | //
 | ||||||
|  | 
 | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include "NativeInvoker.h" | ||||||
|  | 
 | ||||||
|  | /********************
 | ||||||
|  | * FUNCTION CALLING * | ||||||
|  | ********************/ | ||||||
|  | 
 | ||||||
|  | NativeInvoker::NativeInvoker(IPluginContext *pContext, const ke::RefPtr<Native> &native) | ||||||
|  |  : context_(pContext), | ||||||
|  |    m_curparam(0), | ||||||
|  |    m_errorstate(SP_ERROR_NONE), | ||||||
|  |    native_(native) | ||||||
|  | { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | NativeInvoker::~NativeInvoker() | ||||||
|  | { | ||||||
|  |   Cancel(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool | ||||||
|  | NativeInvoker::IsRunnable() | ||||||
|  | { | ||||||
|  |   return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | IPluginContext * | ||||||
|  | NativeInvoker::GetParentContext() | ||||||
|  | { | ||||||
|  |   return context_; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int NativeInvoker::PushCell(cell_t cell) | ||||||
|  | { | ||||||
|  |   if (m_curparam >= SP_MAX_EXEC_PARAMS) | ||||||
|  |     return SetError(SP_ERROR_PARAMS_MAX); | ||||||
|  | 
 | ||||||
|  |   m_info[m_curparam].marked = false; | ||||||
|  |   m_params[m_curparam] = cell; | ||||||
|  |   m_curparam++; | ||||||
|  | 
 | ||||||
|  |   return SP_ERROR_NONE; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int | ||||||
|  | NativeInvoker::PushCellByRef(cell_t *cell, int flags) | ||||||
|  | { | ||||||
|  |   return PushArray(cell, 1, flags); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int | ||||||
|  | NativeInvoker::PushFloat(float number) | ||||||
|  | { | ||||||
|  |   cell_t val = sp::FloatCellUnion(number).cell; | ||||||
|  | 
 | ||||||
|  |   return PushCell(val); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int | ||||||
|  | NativeInvoker::PushFloatByRef(float *number, int flags) | ||||||
|  | { | ||||||
|  |   return PushCellByRef((cell_t *)number, flags); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int | ||||||
|  | NativeInvoker::PushArray(cell_t *inarray, unsigned int cells, int copyback) | ||||||
|  | { | ||||||
|  |   if (m_curparam >= SP_MAX_EXEC_PARAMS) | ||||||
|  |   { | ||||||
|  |     return SetError(SP_ERROR_PARAMS_MAX); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   ParamInfo *info = &m_info[m_curparam]; | ||||||
|  | 
 | ||||||
|  |   info->flags = inarray ? copyback : 0; | ||||||
|  |   info->marked = true; | ||||||
|  |   info->size = cells; | ||||||
|  |   info->str.is_sz = false; | ||||||
|  |   info->orig_addr = inarray; | ||||||
|  | 
 | ||||||
|  |   m_curparam++; | ||||||
|  | 
 | ||||||
|  |   return SP_ERROR_NONE; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int | ||||||
|  | NativeInvoker::PushString(const char *string) | ||||||
|  | { | ||||||
|  |   return _PushString(string, SM_PARAM_STRING_COPY, 0, strlen(string)+1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int | ||||||
|  | NativeInvoker::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags) | ||||||
|  | { | ||||||
|  |   return _PushString(buffer, sz_flags, cp_flags, length); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int | ||||||
|  | NativeInvoker::_PushString(const char *string, int sz_flags, int cp_flags, size_t len) | ||||||
|  | { | ||||||
|  |   if (m_curparam >= SP_MAX_EXEC_PARAMS) | ||||||
|  |     return SetError(SP_ERROR_PARAMS_MAX); | ||||||
|  | 
 | ||||||
|  |   ParamInfo *info = &m_info[m_curparam]; | ||||||
|  | 
 | ||||||
|  |   info->marked = true; | ||||||
|  |   info->orig_addr = (cell_t *)string; | ||||||
|  |   info->flags = cp_flags; | ||||||
|  |   info->size = len; | ||||||
|  |   info->str.sz_flags = sz_flags; | ||||||
|  |   info->str.is_sz = true; | ||||||
|  | 
 | ||||||
|  |   m_curparam++; | ||||||
|  | 
 | ||||||
|  |   return SP_ERROR_NONE; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void | ||||||
|  | NativeInvoker::Cancel() | ||||||
|  | { | ||||||
|  |   if (!m_curparam) | ||||||
|  |     return; | ||||||
|  | 
 | ||||||
|  |   m_errorstate = SP_ERROR_NONE; | ||||||
|  |   m_curparam = 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int | ||||||
|  | NativeInvoker::Execute(cell_t *result, cell_t buffer, cell_t size) | ||||||
|  | { | ||||||
|  |   context_->ClearLastNativeError(); | ||||||
|  | 
 | ||||||
|  |   // For backward compatibility, we have to clear the exception state.
 | ||||||
|  |   // Otherwise code like this:
 | ||||||
|  |   //
 | ||||||
|  |   // static cell_t native(cx, params) {
 | ||||||
|  |   //   for (auto callback : callbacks) {
 | ||||||
|  |   //     callback->Execute();
 | ||||||
|  |   //   }
 | ||||||
|  |   // }
 | ||||||
|  |   //
 | ||||||
|  |   // Could unintentionally leak a pending exception back to the caller,
 | ||||||
|  |   // which wouldn't have happened before the Great Exception Refactoring.
 | ||||||
|  | 
 | ||||||
|  |   SourcePawn::ExceptionHandler eh(context_); | ||||||
|  |   eh.Debug(!size); | ||||||
|  | 
 | ||||||
|  |   if (!Invoke(result)) { | ||||||
|  |     if(size) | ||||||
|  |       context_->StringToLocalUTF8(buffer, size, eh.Message(), NULL); | ||||||
|  |     int Err = context_->GetLastNativeError(); | ||||||
|  |     context_->ClearLastNativeError(); | ||||||
|  |     return Err; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   return SP_ERROR_NONE; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool | ||||||
|  | NativeInvoker::Invoke(cell_t *result) | ||||||
|  | { | ||||||
|  |   if (!IsRunnable()) { | ||||||
|  |     Cancel(); | ||||||
|  |     context_->ReportErrorNumber(SP_ERROR_NOT_RUNNABLE); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |   if (int err = m_errorstate) { | ||||||
|  |     Cancel(); | ||||||
|  |     context_->ReportErrorNumber(err); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   //This is for re-entrancy!
 | ||||||
|  |   cell_t _temp_params[SP_MAX_EXEC_PARAMS + 1]; | ||||||
|  |   cell_t *temp_params = &_temp_params[1]; | ||||||
|  |   ParamInfo temp_info[SP_MAX_EXEC_PARAMS]; | ||||||
|  |   unsigned int numparams = m_curparam; | ||||||
|  |   unsigned int i; | ||||||
|  | 
 | ||||||
|  |   if (numparams) | ||||||
|  |   { | ||||||
|  |     //Save the info locally, then reset it for re-entrant calls.
 | ||||||
|  |     memcpy(temp_info, m_info, numparams * sizeof(ParamInfo)); | ||||||
|  |   } | ||||||
|  |   m_curparam = 0; | ||||||
|  | 
 | ||||||
|  |   /* Initialize 0th parameter */ | ||||||
|  |   _temp_params[0] = numparams; | ||||||
|  | 
 | ||||||
|  |   /* Browse the parameters and build arrays */ | ||||||
|  |   bool ok = true; | ||||||
|  |   for (i=0; i<numparams; i++) { | ||||||
|  |     /* Is this marked as an array? */ | ||||||
|  |     if (temp_info[i].marked) { | ||||||
|  |       if (!temp_info[i].str.is_sz) { | ||||||
|  |         /* Allocate a normal/generic array */ | ||||||
|  |         int err = context_->HeapAlloc( | ||||||
|  |           temp_info[i].size, | ||||||
|  |           &(temp_info[i].local_addr), | ||||||
|  |           &(temp_info[i].phys_addr)); | ||||||
|  |         if (err != SP_ERROR_NONE) { | ||||||
|  |           context_->ReportErrorNumber(err); | ||||||
|  |           ok = false; | ||||||
|  |           break; | ||||||
|  |         } | ||||||
|  |         if (temp_info[i].orig_addr) | ||||||
|  |         { | ||||||
|  |           memcpy(temp_info[i].phys_addr, temp_info[i].orig_addr, sizeof(cell_t) * temp_info[i].size); | ||||||
|  |         } | ||||||
|  |       } else { | ||||||
|  |         /* Calculate cells required for the string */ | ||||||
|  |         size_t cells = (temp_info[i].size + sizeof(cell_t) - 1) / sizeof(cell_t); | ||||||
|  | 
 | ||||||
|  |         /* Allocate the buffer */ | ||||||
|  |         int err = context_->HeapAlloc( | ||||||
|  |           cells, | ||||||
|  |           &(temp_info[i].local_addr), | ||||||
|  |           &(temp_info[i].phys_addr)); | ||||||
|  |         if (err != SP_ERROR_NONE) { | ||||||
|  |           context_->ReportErrorNumber(err); | ||||||
|  |           ok = false; | ||||||
|  |           break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         /* Copy original string if necessary */ | ||||||
|  |         if ((temp_info[i].str.sz_flags & SM_PARAM_STRING_COPY) && (temp_info[i].orig_addr != NULL)) | ||||||
|  |         { | ||||||
|  |           /* Cut off UTF-8 properly */ | ||||||
|  |           if (temp_info[i].str.sz_flags & SM_PARAM_STRING_UTF8) { | ||||||
|  |             context_->StringToLocalUTF8( | ||||||
|  |               temp_info[i].local_addr, | ||||||
|  |               temp_info[i].size, | ||||||
|  |               (const char *)temp_info[i].orig_addr, | ||||||
|  |               NULL); | ||||||
|  |           } | ||||||
|  |           /* Copy a binary blob */ | ||||||
|  |           else if (temp_info[i].str.sz_flags & SM_PARAM_STRING_BINARY) | ||||||
|  |           { | ||||||
|  |             memmove(temp_info[i].phys_addr, temp_info[i].orig_addr, temp_info[i].size); | ||||||
|  |           } | ||||||
|  |           /* Copy ASCII characters */ | ||||||
|  |           else | ||||||
|  |           { | ||||||
|  |             context_->StringToLocal( | ||||||
|  |               temp_info[i].local_addr, | ||||||
|  |               temp_info[i].size, | ||||||
|  |               (const char *)temp_info[i].orig_addr); | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } /* End array/string calculation */ | ||||||
|  |       /* Update the pushed parameter with the byref local address */ | ||||||
|  |       temp_params[i] = temp_info[i].local_addr; | ||||||
|  |     } else { | ||||||
|  |       /* Just copy the value normally */ | ||||||
|  |       temp_params[i] = m_params[i]; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /* Make the call if we can */ | ||||||
|  |   if (ok) | ||||||
|  |   { | ||||||
|  |     *result = native_->func()(context_, _temp_params); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /* i should be equal to the last valid parameter + 1 */ | ||||||
|  |   bool docopies = ok; | ||||||
|  |   while (i--) { | ||||||
|  |     if (!temp_info[i].marked) | ||||||
|  |       continue; | ||||||
|  | 
 | ||||||
|  |     if (docopies && (temp_info[i].flags & SM_PARAM_COPYBACK)) { | ||||||
|  |       if (temp_info[i].orig_addr) { | ||||||
|  |         if (temp_info[i].str.is_sz) { | ||||||
|  |           memcpy(temp_info[i].orig_addr, temp_info[i].phys_addr, temp_info[i].size); | ||||||
|  | 
 | ||||||
|  |         } else { | ||||||
|  |           if (temp_info[i].size == 1) { | ||||||
|  |             *temp_info[i].orig_addr = *(temp_info[i].phys_addr); | ||||||
|  |           } else { | ||||||
|  |             memcpy(temp_info[i].orig_addr, | ||||||
|  |                 temp_info[i].phys_addr, | ||||||
|  |                 temp_info[i].size * sizeof(cell_t)); | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (int err = context_->HeapPop(temp_info[i].local_addr)) | ||||||
|  |       context_->ReportErrorNumber(err); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   return context_->GetLastNativeError() == SP_ERROR_NONE; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int | ||||||
|  | NativeInvoker::SetError(int err) | ||||||
|  | { | ||||||
|  |   m_errorstate = err; | ||||||
|  | 
 | ||||||
|  |   return err; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int NativeInvoker::CallFunction(const cell_t *params, unsigned int num_params, cell_t *result) { return 0; } | ||||||
|  | funcid_t NativeInvoker::GetFunctionID() { return 0; } | ||||||
|  | int NativeInvoker::Execute2(IPluginContext *ctx, cell_t *result) { return 0; } | ||||||
|  | int NativeInvoker::CallFunction2(IPluginContext *ctx, const cell_t *params, unsigned int num_params, cell_t *result) { return 0; } | ||||||
|  | IPluginRuntime *NativeInvoker::GetParentRuntime() { return NULL; } | ||||||
							
								
								
									
										79
									
								
								core/logic/NativeInvoker.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								core/logic/NativeInvoker.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,79 @@ | |||||||
|  | // vim: set sts=2 ts=8 sw=2 tw=99 et:
 | ||||||
|  | //
 | ||||||
|  | // Copyright (C) 2006-2015 AlliedModders LLC
 | ||||||
|  | //
 | ||||||
|  | // This file is part of SourcePawn. SourcePawn is free software: you can
 | ||||||
|  | // redistribute it and/or modify it under the terms of the GNU General Public
 | ||||||
|  | // License as published by the Free Software Foundation, either version 3 of
 | ||||||
|  | // the License, or (at your option) any later version.
 | ||||||
|  | //
 | ||||||
|  | // You should have received a copy of the GNU General Public License along with
 | ||||||
|  | // SourcePawn. If not, see http://www.gnu.org/licenses/.
 | ||||||
|  | //
 | ||||||
|  | #ifndef _INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_ | ||||||
|  | #define _INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_ | ||||||
|  | 
 | ||||||
|  | #include <sp_vm_api.h> | ||||||
|  | #include <amtl/am-autoptr.h> | ||||||
|  | #include <amtl/am-refcounting.h> | ||||||
|  | #include "Native.h" | ||||||
|  | 
 | ||||||
|  | struct ParamInfo | ||||||
|  | { | ||||||
|  |   int flags;      /* Copy-back flags */ | ||||||
|  |   bool marked;    /* Whether this is marked as being used */ | ||||||
|  |   cell_t local_addr;  /* Local address to free */ | ||||||
|  |   cell_t *phys_addr;  /* Physical address of our copy */ | ||||||
|  |   cell_t *orig_addr;  /* Original address to copy back to */ | ||||||
|  |   ucell_t size;    /* Size of array in bytes */ | ||||||
|  |   struct { | ||||||
|  |     bool is_sz;    /* is a string */ | ||||||
|  |     int sz_flags;  /* has sz flags */ | ||||||
|  |   } str; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | class NativeInvoker : public IPluginFunction | ||||||
|  | { | ||||||
|  |  public: | ||||||
|  |   NativeInvoker(IPluginContext *pContext, const ke::RefPtr<Native> &native); | ||||||
|  |   virtual ~NativeInvoker(); | ||||||
|  | 
 | ||||||
|  |  public: | ||||||
|  |   int PushCell(cell_t cell); | ||||||
|  |   int PushCellByRef(cell_t *cell, int flags); | ||||||
|  |   int PushFloat(float number); | ||||||
|  |   int PushFloatByRef(float *number, int flags); | ||||||
|  |   int PushArray(cell_t *inarray, unsigned int cells, int copyback); | ||||||
|  |   int PushString(const char *string); | ||||||
|  |   int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags); | ||||||
|  |   int Execute(cell_t *result, cell_t buffer=0, cell_t size=0); | ||||||
|  |   void Cancel(); | ||||||
|  |   int CallFunction(const cell_t *params, unsigned int num_params, cell_t *result); | ||||||
|  |   IPluginContext *GetParentContext(); | ||||||
|  |   bool Invoke(cell_t *result); | ||||||
|  |   bool IsRunnable(); | ||||||
|  |   funcid_t GetFunctionID(); | ||||||
|  |   int Execute2(IPluginContext *ctx, cell_t *result); | ||||||
|  |   int CallFunction2(IPluginContext *ctx, | ||||||
|  |     const cell_t *params, | ||||||
|  |     unsigned int num_params, | ||||||
|  |     cell_t *result); | ||||||
|  |   IPluginRuntime *GetParentRuntime(); | ||||||
|  |   const char *DebugName() { | ||||||
|  |     return native_->name(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |  private: | ||||||
|  |   int _PushString(const char *string, int sz_flags, int cp_flags, size_t len); | ||||||
|  |   int SetError(int err); | ||||||
|  | 
 | ||||||
|  |  private: | ||||||
|  |   IPluginContext *context_; | ||||||
|  |   cell_t m_params[SP_MAX_EXEC_PARAMS]; | ||||||
|  |   ParamInfo m_info[SP_MAX_EXEC_PARAMS]; | ||||||
|  |   unsigned int m_curparam; | ||||||
|  |   int m_errorstate; | ||||||
|  |   ke::RefPtr<Native> native_; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #endif //_INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_
 | ||||||
| @ -35,6 +35,8 @@ | |||||||
| #include <IForwardSys.h> | #include <IForwardSys.h> | ||||||
| #include <ISourceMod.h> | #include <ISourceMod.h> | ||||||
| #include <amtl/am-autoptr.h> | #include <amtl/am-autoptr.h> | ||||||
|  | #include "ShareSys.h" | ||||||
|  | #include "NativeInvoker.h" | ||||||
| 
 | 
 | ||||||
| HandleType_t g_GlobalFwdType = 0; | HandleType_t g_GlobalFwdType = 0; | ||||||
| HandleType_t g_PrivateFwdType = 0; | HandleType_t g_PrivateFwdType = 0; | ||||||
| @ -43,6 +45,7 @@ static bool s_CallStarted = false; | |||||||
| static ICallable *s_pCallable = NULL; | static ICallable *s_pCallable = NULL; | ||||||
| static IPluginFunction *s_pFunction = NULL; | static IPluginFunction *s_pFunction = NULL; | ||||||
| static IForward *s_pForward = NULL; | static IForward *s_pForward = NULL; | ||||||
|  | static NativeInvoker *s_pInvoker = NULL; | ||||||
| 
 | 
 | ||||||
| class ForwardNativeHelpers :  | class ForwardNativeHelpers :  | ||||||
| 	public SMGlobalClass, | 	public SMGlobalClass, | ||||||
| @ -102,6 +105,9 @@ inline void ResetCall() | |||||||
| 	s_pFunction = NULL; | 	s_pFunction = NULL; | ||||||
| 	s_pForward = NULL; | 	s_pForward = NULL; | ||||||
| 	s_pCallable = NULL; | 	s_pCallable = NULL; | ||||||
|  | 	if(s_pInvoker) | ||||||
|  | 		delete s_pInvoker; | ||||||
|  | 	s_pInvoker = NULL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static cell_t sm_GetFunctionByName(IPluginContext *pContext, const cell_t *params) | static cell_t sm_GetFunctionByName(IPluginContext *pContext, const cell_t *params) | ||||||
| @ -366,6 +372,27 @@ static cell_t sm_CallStartForward(IPluginContext *pContext, const cell_t *params | |||||||
| 	return 1; | 	return 1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static cell_t sm_CallStartNative(IPluginContext *pContext, const cell_t *params) | ||||||
|  | { | ||||||
|  | 	ResetCall(); | ||||||
|  | 
 | ||||||
|  | 	char *name; | ||||||
|  | 	pContext->LocalToString(params[1], &name); | ||||||
|  | 
 | ||||||
|  | 	ke::RefPtr<Native> pNative = g_ShareSys.FindNative(name); | ||||||
|  | 
 | ||||||
|  | 	if (!pNative) | ||||||
|  | 		return 0;//pContext->ThrowNativeError("Invalid native \"%s\"", name);
 | ||||||
|  | 
 | ||||||
|  | 	s_pInvoker = new NativeInvoker(pContext, pNative); | ||||||
|  | 
 | ||||||
|  | 	s_pCallable = static_cast<ICallable *>(s_pInvoker); | ||||||
|  | 
 | ||||||
|  | 	s_CallStarted = true; | ||||||
|  | 
 | ||||||
|  | 	return 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static cell_t sm_CallPushCell(IPluginContext *pContext, const cell_t *params) | static cell_t sm_CallPushCell(IPluginContext *pContext, const cell_t *params) | ||||||
| { | { | ||||||
| 	int err; | 	int err; | ||||||
| @ -656,6 +683,39 @@ static cell_t sm_CallFinish(IPluginContext *pContext, const cell_t *params) | |||||||
| 		IForward *pForward = s_pForward; | 		IForward *pForward = s_pForward; | ||||||
| 		ResetCall(); | 		ResetCall(); | ||||||
| 		err = pForward->Execute(result, NULL); | 		err = pForward->Execute(result, NULL); | ||||||
|  | 	} else if (s_pInvoker) { | ||||||
|  | 		err = s_pInvoker->Execute(result); | ||||||
|  | 		ResetCall(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return err; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static cell_t sm_CallFinishEx(IPluginContext *pContext, const cell_t *params) | ||||||
|  | { | ||||||
|  | 	int err = SP_ERROR_NOT_RUNNABLE; | ||||||
|  | 	cell_t *result; | ||||||
|  | 
 | ||||||
|  | 	if (!s_CallStarted) | ||||||
|  | 	{ | ||||||
|  | 		return pContext->ThrowNativeError("Cannot finish call when there is no call in progress"); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	pContext->LocalToPhysAddr(params[1], &result); | ||||||
|  | 
 | ||||||
|  | 	// Note: Execute() swallows exceptions, so this is okay.
 | ||||||
|  | 	if (s_pFunction) | ||||||
|  | 	{ | ||||||
|  | 		IPluginFunction *pFunction = s_pFunction; | ||||||
|  | 		ResetCall(); | ||||||
|  | 		err = pFunction->Execute(result, params[2], params[3]); | ||||||
|  | 	} else if (s_pForward) { | ||||||
|  | 		IForward *pForward = s_pForward; | ||||||
|  | 		ResetCall(); | ||||||
|  | 		err = pForward->Execute(result, NULL); | ||||||
|  | 	} else if (s_pInvoker) { | ||||||
|  | 		err = s_pInvoker->Execute(result, params[2], params[3]); | ||||||
|  | 		ResetCall(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return err; | 	return err; | ||||||
| @ -742,6 +802,7 @@ REGISTER_NATIVES(functionNatives) | |||||||
| 	{"RemoveAllFromForward",                sm_RemoveAllFromForward}, | 	{"RemoveAllFromForward",                sm_RemoveAllFromForward}, | ||||||
| 	{"Call_StartFunction",                  sm_CallStartFunction}, | 	{"Call_StartFunction",                  sm_CallStartFunction}, | ||||||
| 	{"Call_StartForward",                   sm_CallStartForward}, | 	{"Call_StartForward",                   sm_CallStartForward}, | ||||||
|  | 	{"Call_StartNative",                    sm_CallStartNative}, | ||||||
| 	{"Call_PushCell",                       sm_CallPushCell}, | 	{"Call_PushCell",                       sm_CallPushCell}, | ||||||
| 	{"Call_PushCellRef",                    sm_CallPushCellRef}, | 	{"Call_PushCellRef",                    sm_CallPushCellRef}, | ||||||
| 	{"Call_PushFloat",                      sm_CallPushFloat}, | 	{"Call_PushFloat",                      sm_CallPushFloat}, | ||||||
| @ -753,6 +814,7 @@ REGISTER_NATIVES(functionNatives) | |||||||
| 	{"Call_PushNullVector",                 sm_CallPushNullVector}, | 	{"Call_PushNullVector",                 sm_CallPushNullVector}, | ||||||
| 	{"Call_PushNullString",                 sm_CallPushNullString}, | 	{"Call_PushNullString",                 sm_CallPushNullString}, | ||||||
| 	{"Call_Finish",                         sm_CallFinish}, | 	{"Call_Finish",                         sm_CallFinish}, | ||||||
|  | 	{"Call_FinishEx",                       sm_CallFinishEx}, | ||||||
| 	{"Call_Cancel",                         sm_CallCancel}, | 	{"Call_Cancel",                         sm_CallCancel}, | ||||||
| 	{"RequestFrame",                        sm_AddFrameAction}, | 	{"RequestFrame",                        sm_AddFrameAction}, | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -293,6 +293,17 @@ native void Call_StartForward(Handle fwd); | |||||||
|  */ |  */ | ||||||
| native void Call_StartFunction(Handle plugin, Function func); | native void Call_StartFunction(Handle plugin, Function func); | ||||||
| 
 | 
 | ||||||
|  | /** | ||||||
|  |  * Starts a call to a native. | ||||||
|  |  * | ||||||
|  |  * @note Cannot be used during an incomplete call. | ||||||
|  |  * | ||||||
|  |  * @param name				Name of the native. | ||||||
|  |  * @return					True on success, false otherwise. | ||||||
|  |  * @error					Invalid function, or called before another call has completed. | ||||||
|  |  */ | ||||||
|  | native bool Call_StartNative(const char[] name); | ||||||
|  | 
 | ||||||
| /** | /** | ||||||
|  * Pushes a cell onto the current call. |  * Pushes a cell onto the current call. | ||||||
|  * |  * | ||||||
| @ -416,6 +427,20 @@ native void Call_PushNullString(); | |||||||
|  */ |  */ | ||||||
| native int Call_Finish(any &result=0); | native int Call_Finish(any &result=0); | ||||||
| 
 | 
 | ||||||
|  | /** | ||||||
|  |  * Completes a call to a function or forward's call list. | ||||||
|  |  * Catches exceptions thrown by the native. | ||||||
|  |  * | ||||||
|  |  * @note Cannot be used before a call has been started. | ||||||
|  |  * | ||||||
|  |  * @param result			Return value of function or forward's call list. | ||||||
|  |  * @param exception			Buffer to store the exception in. | ||||||
|  |  * @param maxlength			Maximum length of the buffer. | ||||||
|  |  * @return					SP_ERROR_NONE on success, any other integer on failure. | ||||||
|  |  * @error					Called before a call has been started. | ||||||
|  |  */ | ||||||
|  | native int Call_FinishEx(any &result=0, char[] exception, int maxlength); | ||||||
|  | 
 | ||||||
| /** | /** | ||||||
|  * Cancels a call to a function or forward's call list. |  * Cancels a call to a function or forward's call list. | ||||||
|  * |  * | ||||||
|  | |||||||
| @ -1 +1 @@ | |||||||
| Subproject commit 7ba3e384e29ccdb5dbd3ac4a0fda16fd0a0144a8 | Subproject commit 04eafd88631e7a3ba1de6bc7228af0e3d5443f0b | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user