Extend function calling API for natives and allow catching exceptions.
Change sourcepawn url.
This commit is contained in:
		
							parent
							
								
									82628cfc5a
								
							
						
					
					
						commit
						da1cd9eb11
					
				
							
								
								
									
										2
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							| @ -3,4 +3,4 @@ | ||||
| 	url = https://github.com/alliedmodders/amtl | ||||
| [submodule "sourcepawn"] | ||||
| 	path = sourcepawn | ||||
| 	url = https://github.com/alliedmodders/sourcepawn | ||||
| 	url = https://github.com/BotoX/sourcepawn.git | ||||
|  | ||||
| @ -83,10 +83,12 @@ binary.sources += [ | ||||
|   'frame_tasks.cpp', | ||||
|   'smn_halflife.cpp', | ||||
|   'FrameIterator.cpp', | ||||
|   'NativeInvoker.cpp', | ||||
| ] | ||||
| if builder.target.platform == 'windows': | ||||
|   binary.sources += ['thread/WinThreads.cpp'] | ||||
| else: | ||||
|   binary.sources += ['thread/PosixThreads.cpp'] | ||||
| 
 | ||||
| 
 | ||||
| SM.binaries += [builder.Add(binary)] | ||||
|  | ||||
							
								
								
									
										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 <ISourceMod.h> | ||||
| #include <amtl/am-autoptr.h> | ||||
| #include "ShareSys.h" | ||||
| #include "NativeInvoker.h" | ||||
| 
 | ||||
| HandleType_t g_GlobalFwdType = 0; | ||||
| HandleType_t g_PrivateFwdType = 0; | ||||
| @ -43,6 +45,7 @@ static bool s_CallStarted = false; | ||||
| static ICallable *s_pCallable = NULL; | ||||
| static IPluginFunction *s_pFunction = NULL; | ||||
| static IForward *s_pForward = NULL; | ||||
| static NativeInvoker *s_pInvoker = NULL; | ||||
| 
 | ||||
| class ForwardNativeHelpers :  | ||||
| 	public SMGlobalClass, | ||||
| @ -102,6 +105,9 @@ inline void ResetCall() | ||||
| 	s_pFunction = NULL; | ||||
| 	s_pForward = NULL; | ||||
| 	s_pCallable = NULL; | ||||
| 	if(s_pInvoker) | ||||
| 		delete s_pInvoker; | ||||
| 	s_pInvoker = NULL; | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
| } | ||||
| 
 | ||||
| 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) | ||||
| { | ||||
| 	int err; | ||||
| @ -656,6 +683,39 @@ static cell_t sm_CallFinish(IPluginContext *pContext, const cell_t *params) | ||||
| 		IForward *pForward = s_pForward; | ||||
| 		ResetCall(); | ||||
| 		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; | ||||
| @ -742,6 +802,7 @@ REGISTER_NATIVES(functionNatives) | ||||
| 	{"RemoveAllFromForward",	sm_RemoveAllFromForward}, | ||||
| 	{"Call_StartFunction",		sm_CallStartFunction}, | ||||
| 	{"Call_StartForward",		sm_CallStartForward}, | ||||
| 	{"Call_StartNative",		sm_CallStartNative}, | ||||
| 	{"Call_PushCell",			sm_CallPushCell}, | ||||
| 	{"Call_PushCellRef",		sm_CallPushCellRef}, | ||||
| 	{"Call_PushFloat",			sm_CallPushFloat}, | ||||
| @ -753,6 +814,7 @@ REGISTER_NATIVES(functionNatives) | ||||
| 	{"Call_PushNullVector",		sm_CallPushNullVector}, | ||||
| 	{"Call_PushNullString",		sm_CallPushNullString}, | ||||
| 	{"Call_Finish",				sm_CallFinish}, | ||||
| 	{"Call_FinishEx",			sm_CallFinishEx}, | ||||
| 	{"Call_Cancel",				sm_CallCancel}, | ||||
| 	{"RequestFrame",			sm_AddFrameAction}, | ||||
| 	{NULL,						NULL}, | ||||
|  | ||||
| @ -221,10 +221,20 @@ native void Call_StartForward(Handle fwd); | ||||
|  * @param plugin			Handle of the plugin that contains the function. | ||||
|  *							Pass INVALID_HANDLE to specify the calling plugin. | ||||
|  * @param func				Function to call. | ||||
|  * @error					Invalid or corrupt plugin handle, invalid function, or called before another call has completed. | ||||
|  */ | ||||
| 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. | ||||
|  * | ||||
| @ -348,6 +358,20 @@ native void Call_PushNullString(); | ||||
|  */ | ||||
| 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. | ||||
|  * | ||||
|  | ||||
| @ -1 +1 @@ | ||||
| Subproject commit c78349382d97d5a9f20b49975c47d9bb805c125d | ||||
| Subproject commit e5997209dbc1da2f2a082b8b837e75907032f2df | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user