fixed amb200, added native test suite

This commit is contained in:
David Anderson 2007-04-16 17:08:15 +00:00
parent 5d4669d52e
commit de530e2ca3
3 changed files with 117 additions and 68 deletions

View File

@ -46,12 +46,16 @@
//With the exception for param_convert, which was written by //With the exception for param_convert, which was written by
// Julien "dJeyL" Laurent // Julien "dJeyL" Laurent
CStack<int> g_ErrorStk;
CVector<regnative *> g_RegNatives; CVector<regnative *> g_RegNatives;
CStack<regnative *> g_NativeStack;
static char g_errorStr[512] = {0}; static char g_errorStr[512] = {0};
bool g_Initialized = false; bool g_Initialized = false;
/* Stack stuff */
regnative *g_pCurNative = NULL;
AMX *g_pCaller = NULL;
cell g_Params[CALLFUNC_MAXPARAMS];
int g_CurError = AMX_ERR_NONE;
int amxx_DynaCallback(int idx, AMX *amx, cell *params) int amxx_DynaCallback(int idx, AMX *amx, cell *params)
{ {
if (idx < 0 || idx >= (int)g_RegNatives.size()) if (idx < 0 || idx >= (int)g_RegNatives.size())
@ -79,37 +83,55 @@ int amxx_DynaCallback(int idx, AMX *amx, cell *params)
return 0; return 0;
} }
if (pNative->caller) /* Save old values on ZE STACK */
AMX *pSaveCaller = g_pCaller;
cell saveParams[CALLFUNC_MAXPARAMS];
regnative *pSaveNative = g_pCurNative;
int saveError = g_CurError;
if (pSaveNative)
{ {
LogError(amx, AMX_ERR_NATIVE, "Bug caught! Please contact the AMX Mod X Dev Team."); for (ucell i = 0; i <= g_Params[0] / sizeof(cell); i++)
return 0; {
saveParams[i] = g_Params[i];
}
} }
//parameter stack /* Save current info */
//NOTE: it is possible that recursive register native calling g_CurError = AMX_ERR_NONE;
// could potentially be somehow damaged here. g_pCaller = amx;
//so, a :TODO: - make the stack unique, rather than a known ptr g_pCurNative = pNative;
pNative->caller = amx;
int err = 0; int err = 0;
cell ret = 0; cell ret = 0;
g_ErrorStk.push(0);
g_NativeStack.push(pNative);
if (pNative->style == 0) if (pNative->style == 0)
{ {
amx_Push(pNative->amx, numParams); amx_Push(pNative->amx, numParams);
amx_Push(pNative->amx, pPlugin->getId()); amx_Push(pNative->amx, pPlugin->getId());
for (int i=numParams; i>=0; i--) for (int i=numParams; i>=0; i--)
pNative->params[i] = params[i]; {
g_Params[i] = params[i];
}
} else if (pNative->style == 1) { } else if (pNative->style == 1) {
//use dJeyL's system .. very clever! /**
* use dJeyL's system .. very clever!
* NOTE: clever, but doesn't work at all since the JIT does bounds checking
* this should REALLY be deprecated
*/
for (int i=numParams; i>=1; i--) for (int i=numParams; i>=1; i--)
{
amx_Push(pNative->amx, params[i]); amx_Push(pNative->amx, params[i]);
} }
}
Debugger *pDebugger = (Debugger *)pNative->amx->userdata[UD_DEBUGGER]; Debugger *pDebugger = (Debugger *)pNative->amx->userdata[UD_DEBUGGER];
if (pDebugger) if (pDebugger)
{
pDebugger->BeginExec(); pDebugger->BeginExec();
}
err=amx_Exec(pNative->amx, &ret, pNative->func); err=amx_Exec(pNative->amx, &ret, pNative->func);
if (err != AMX_ERR_NONE) if (err != AMX_ERR_NONE)
{ {
if (pDebugger && pDebugger->ErrorExists()) if (pDebugger && pDebugger->ErrorExists())
@ -122,15 +144,26 @@ int amxx_DynaCallback(int idx, AMX *amx, cell *params)
pNative->amx->error = AMX_ERR_NONE; pNative->amx->error = AMX_ERR_NONE;
//furthermore, log an error in the parent plugin. //furthermore, log an error in the parent plugin.
LogError(amx, AMX_ERR_NATIVE, "Unhandled dynamic native error"); LogError(amx, AMX_ERR_NATIVE, "Unhandled dynamic native error");
} else if (g_ErrorStk.front()) { } else if (g_CurError != AMX_ERR_NONE) {
LogError(amx, g_ErrorStk.front(), g_errorStr); LogError(amx, g_CurError, g_errorStr);
} }
if (pDebugger)
pDebugger->EndExec();
g_NativeStack.pop();
g_ErrorStk.pop();
pNative->caller = NULL; if (pDebugger)
{
pDebugger->EndExec();
}
/* Restore everything */
g_pCurNative = pSaveNative;
g_CurError = saveError;
g_pCaller = pSaveCaller;
if (pSaveNative)
{
for (ucell i = 0; i <= saveParams[0] / sizeof(cell); i++)
{
g_Params[i] = saveParams[i];
}
}
return ret; return ret;
} }
@ -138,7 +171,9 @@ int amxx_DynaCallback(int idx, AMX *amx, cell *params)
AMX_NATIVE_INFO *BuildNativeTable() AMX_NATIVE_INFO *BuildNativeTable()
{ {
if (g_RegNatives.size() < 1) if (g_RegNatives.size() < 1)
{
return NULL; return NULL;
}
AMX_NATIVE_INFO *pNatives = new AMX_NATIVE_INFO[g_RegNatives.size() + 1]; AMX_NATIVE_INFO *pNatives = new AMX_NATIVE_INFO[g_RegNatives.size() + 1];
@ -164,8 +199,7 @@ static cell AMX_NATIVE_CALL log_error(AMX *amx, cell *params)
char *err = format_amxstring(amx, params, 2, len); char *err = format_amxstring(amx, params, 2, len);
_snprintf(g_errorStr, sizeof(g_errorStr), "%s", err); _snprintf(g_errorStr, sizeof(g_errorStr), "%s", err);
g_ErrorStk.pop(); g_CurError = params[1];
g_ErrorStk.push(params[1]);
return 1; return 1;
} }
@ -173,13 +207,12 @@ static cell AMX_NATIVE_CALL log_error(AMX *amx, cell *params)
//get_string(param, dest[], len) //get_string(param, dest[], len)
static cell AMX_NATIVE_CALL get_string(AMX *amx, cell *params) static cell AMX_NATIVE_CALL get_string(AMX *amx, cell *params)
{ {
if (!g_NativeStack.size()) if (!g_pCurNative || (g_pCaller != amx))
{ {
LogError(amx, AMX_ERR_NATIVE, "Not currently in a dynamic native"); LogError(amx, AMX_ERR_NATIVE, "Not currently in a dynamic native");
return 0; return 0;
} }
regnative *pNative = g_NativeStack.front(); if (g_pCurNative->style)
if (pNative->style)
{ {
LogError(amx, AMX_ERR_NATIVE, "Wrong style of dynamic native"); LogError(amx, AMX_ERR_NATIVE, "Wrong style of dynamic native");
return 0; return 0;
@ -187,20 +220,19 @@ static cell AMX_NATIVE_CALL get_string(AMX *amx, cell *params)
int p = params[1]; int p = params[1];
int len; int len;
char *str = get_amxstring(pNative->caller, pNative->params[p], 0, len); char *str = get_amxstring(g_pCaller, g_Params[p], 0, len);
return set_amxstring(amx, params[2], str, params[3]); return set_amxstring(amx, params[2], str, params[3]);
} }
//set_string(param, source[], maxlen) //set_string(param, source[], maxlen)
static cell AMX_NATIVE_CALL set_string(AMX *amx, cell *params) static cell AMX_NATIVE_CALL set_string(AMX *amx, cell *params)
{ {
if (!g_NativeStack.size()) if (!g_pCurNative || (g_pCaller != amx))
{ {
LogError(amx, AMX_ERR_NATIVE, "Not currently in a dynamic native"); LogError(amx, AMX_ERR_NATIVE, "Not currently in a dynamic native");
return 0; return 0;
} }
regnative *pNative = g_NativeStack.front(); if (g_pCurNative->style)
if (pNative->style)
{ {
LogError(amx, AMX_ERR_NATIVE, "Wrong style of dynamic native"); LogError(amx, AMX_ERR_NATIVE, "Wrong style of dynamic native");
return 0; return 0;
@ -210,46 +242,44 @@ static cell AMX_NATIVE_CALL set_string(AMX *amx, cell *params)
int len; int len;
char *str = get_amxstring(amx, params[2], 0, len); char *str = get_amxstring(amx, params[2], 0, len);
return set_amxstring(pNative->caller, pNative->params[p], str, params[3]); return set_amxstring(g_pCaller, g_Params[p], str, params[3]);
} }
//get a byvalue parameter //get a byvalue parameter
//get_param(num) //get_param(num)
static cell AMX_NATIVE_CALL get_param(AMX *amx, cell *params) static cell AMX_NATIVE_CALL get_param(AMX *amx, cell *params)
{ {
if (!g_NativeStack.size()) if (!g_pCurNative || (g_pCaller != amx))
{ {
LogError(amx, AMX_ERR_NATIVE, "Not currently in a dynamic native"); LogError(amx, AMX_ERR_NATIVE, "Not currently in a dynamic native");
return 0; return 0;
} }
regnative *pNative = g_NativeStack.front(); if (g_pCurNative->style)
if (pNative->style)
{ {
LogError(amx, AMX_ERR_NATIVE, "Wrong style of dynamic native"); LogError(amx, AMX_ERR_NATIVE, "Wrong style of dynamic native");
return 0; return 0;
} }
int p = params[1]; int p = params[1];
return pNative->params[p]; return g_Params[p];
} }
//get_param_byref(num) //get_param_byref(num)
static cell AMX_NATIVE_CALL get_param_byref(AMX *amx, cell *params) static cell AMX_NATIVE_CALL get_param_byref(AMX *amx, cell *params)
{ {
if (!g_NativeStack.size()) if (!g_pCurNative || (g_pCaller != amx))
{ {
LogError(amx, AMX_ERR_NATIVE, "Not currently in a dynamic native"); LogError(amx, AMX_ERR_NATIVE, "Not currently in a dynamic native");
return 0; return 0;
} }
regnative *pNative = g_NativeStack.front(); if (g_pCurNative->style)
if (pNative->style)
{ {
LogError(amx, AMX_ERR_NATIVE, "Wrong style of dynamic native"); LogError(amx, AMX_ERR_NATIVE, "Wrong style of dynamic native");
return 0; return 0;
} }
int p = params[1]; int p = params[1];
cell *addr = get_amxaddr(pNative->caller, pNative->params[p]); cell *addr = get_amxaddr(g_pCaller, g_Params[p]);
return addr[0]; return addr[0];
} }
@ -257,20 +287,19 @@ static cell AMX_NATIVE_CALL get_param_byref(AMX *amx, cell *params)
//set_param_byref(num, val) //set_param_byref(num, val)
static cell AMX_NATIVE_CALL set_param_byref(AMX *amx, cell *params) static cell AMX_NATIVE_CALL set_param_byref(AMX *amx, cell *params)
{ {
if (!g_NativeStack.size()) if (!g_pCurNative || (g_pCaller != amx))
{ {
LogError(amx, AMX_ERR_NATIVE, "Not currently in a dynamic native"); LogError(amx, AMX_ERR_NATIVE, "Not currently in a dynamic native");
return 0; return 0;
} }
regnative *pNative = g_NativeStack.front(); if (g_pCurNative->style)
if (pNative->style)
{ {
LogError(amx, AMX_ERR_NATIVE, "Wrong style of dynamic native"); LogError(amx, AMX_ERR_NATIVE, "Wrong style of dynamic native");
return 0; return 0;
} }
int p = params[1]; int p = params[1];
cell *addr = get_amxaddr(pNative->caller, pNative->params[p]); cell *addr = get_amxaddr(g_pCaller, g_Params[p]);
addr[0] = params[2]; addr[0] = params[2];
@ -280,20 +309,19 @@ static cell AMX_NATIVE_CALL set_param_byref(AMX *amx, cell *params)
//get_array(param, dest[], size) //get_array(param, dest[], size)
static cell AMX_NATIVE_CALL get_array(AMX *amx, cell *params) static cell AMX_NATIVE_CALL get_array(AMX *amx, cell *params)
{ {
if (!g_NativeStack.size()) if (!g_pCurNative || (g_pCaller != amx))
{ {
LogError(amx, AMX_ERR_NATIVE, "Not currently in a dynamic native"); LogError(amx, AMX_ERR_NATIVE, "Not currently in a dynamic native");
return 0; return 0;
} }
regnative *pNative = g_NativeStack.front(); if (g_pCurNative->style)
if (pNative->style)
{ {
LogError(amx, AMX_ERR_NATIVE, "Wrong style of dynamic native"); LogError(amx, AMX_ERR_NATIVE, "Wrong style of dynamic native");
return 0; return 0;
} }
int p = params[1]; int p = params[1];
cell *source = get_amxaddr(pNative->caller, pNative->params[p]); cell *source = get_amxaddr(g_pCaller, g_Params[p]);
cell *dest = get_amxaddr(amx, params[2]); cell *dest = get_amxaddr(amx, params[2]);
int size = params[3]; int size = params[3];
@ -306,20 +334,19 @@ static cell AMX_NATIVE_CALL get_array(AMX *amx, cell *params)
//set_array(param, source[], size) //set_array(param, source[], size)
static cell AMX_NATIVE_CALL set_array(AMX *amx, cell *params) static cell AMX_NATIVE_CALL set_array(AMX *amx, cell *params)
{ {
if (!g_NativeStack.size()) if (!g_pCurNative || (g_pCaller != amx))
{ {
LogError(amx, AMX_ERR_NATIVE, "Not currently in a dynamic native"); LogError(amx, AMX_ERR_NATIVE, "Not currently in a dynamic native");
return 0; return 0;
} }
regnative *pNative = g_NativeStack.front(); if (g_pCurNative->style)
if (pNative->style)
{ {
LogError(amx, AMX_ERR_NATIVE, "Wrong style of dynamic native"); LogError(amx, AMX_ERR_NATIVE, "Wrong style of dynamic native");
return 0; return 0;
} }
int p = params[1]; int p = params[1];
cell *dest = get_amxaddr(pNative->caller, pNative->params[p]); cell *dest = get_amxaddr(g_pCaller, g_Params[p]);
cell *source = get_amxaddr(amx, params[2]); cell *source = get_amxaddr(amx, params[2]);
int size = params[3]; int size = params[3];
@ -331,15 +358,13 @@ static cell AMX_NATIVE_CALL set_array(AMX *amx, cell *params)
static cell AMX_NATIVE_CALL vdformat(AMX *amx, cell *params) static cell AMX_NATIVE_CALL vdformat(AMX *amx, cell *params)
{ {
if (!g_NativeStack.size()) if (!g_pCurNative || (g_pCaller != amx))
{ {
LogError(amx, AMX_ERR_NATIVE, "Not currently in a dynamic native"); LogError(amx, AMX_ERR_NATIVE, "Not currently in a dynamic native");
return 0; return 0;
} }
regnative *pNative = g_NativeStack.front(); if (g_pCurNative->style)
if (pNative->style)
{ {
LogError(amx, AMX_ERR_NATIVE, "Wrong style of dynamic native"); LogError(amx, AMX_ERR_NATIVE, "Wrong style of dynamic native");
return 0; return 0;
@ -348,10 +373,7 @@ static cell AMX_NATIVE_CALL vdformat(AMX *amx, cell *params)
int vargPos = static_cast<int>(params[4]); int vargPos = static_cast<int>(params[4]);
int fargPos = static_cast<int>(params[3]); int fargPos = static_cast<int>(params[3]);
/** get the parent parameter array */ cell max = g_Params[0] / sizeof(cell);
cell *local_params = pNative->params;
cell max = local_params[0] / sizeof(cell);
if (vargPos > (int)max + 1) if (vargPos > (int)max + 1)
{ {
LogError(amx, AMX_ERR_NATIVE, "Invalid vararg parameter passed: %d", vargPos); LogError(amx, AMX_ERR_NATIVE, "Invalid vararg parameter passed: %d", vargPos);
@ -374,7 +396,7 @@ static cell AMX_NATIVE_CALL vdformat(AMX *amx, cell *params)
} }
fmt = get_amxaddr(amx, params[5]); fmt = get_amxaddr(amx, params[5]);
} else { } else {
fmt = get_amxaddr(pNative->caller, pNative->params[fargPos]); fmt = get_amxaddr(g_pCaller, g_Params[fargPos]);
} }
cell *realdest = get_amxaddr(amx, params[1]); cell *realdest = get_amxaddr(amx, params[1]);
size_t maxlen = static_cast<size_t>(params[2]); size_t maxlen = static_cast<size_t>(params[2]);
@ -385,7 +407,7 @@ static cell AMX_NATIVE_CALL vdformat(AMX *amx, cell *params)
dest = cpbuf; dest = cpbuf;
/* perform format */ /* perform format */
size_t total = atcprintf(dest, maxlen, fmt, pNative->caller, local_params, &vargPos); size_t total = atcprintf(dest, maxlen, fmt, g_pCaller, g_Params, &vargPos);
/* copy back */ /* copy back */
memcpy(realdest, dest, (total+1) * sizeof(cell)); memcpy(realdest, dest, (total+1) * sizeof(cell));
@ -399,20 +421,19 @@ static cell AMX_NATIVE_CALL vdformat(AMX *amx, cell *params)
//I've no idea how he thought of this, but it's great. No idea how well it works. //I've no idea how he thought of this, but it's great. No idea how well it works.
static cell AMX_NATIVE_CALL param_convert(AMX *amx, cell *params) static cell AMX_NATIVE_CALL param_convert(AMX *amx, cell *params)
{ {
if (!g_NativeStack.size()) if (!g_pCurNative || (g_pCaller != amx))
{ {
LogError(amx, AMX_ERR_NATIVE, "Not currently in a dynamic native"); LogError(amx, AMX_ERR_NATIVE, "Not currently in a dynamic native");
return 0; return 0;
} }
regnative *pNative = g_NativeStack.front(); if (g_pCurNative->style != 1)
if (pNative->style != 1)
{ {
LogError(amx, AMX_ERR_NATIVE, "Wrong style of dynamic native"); LogError(amx, AMX_ERR_NATIVE, "Wrong style of dynamic native");
return 0; return 0;
} }
cell p = params[1]; cell p = params[1];
AMX *caller = pNative->caller; AMX *caller = g_pCaller;
unsigned char *data =amx->base+(int)((AMX_HEADER *)amx->base)->dat; unsigned char *data =amx->base+(int)((AMX_HEADER *)amx->base)->dat;
unsigned char *realdata = caller->base+(int)((AMX_HEADER *)caller->base)->dat; unsigned char *realdata = caller->base+(int)((AMX_HEADER *)caller->base)->dat;
@ -454,7 +475,6 @@ static cell AMX_NATIVE_CALL register_native(AMX *amx, cell *params)
regnative *pNative = new regnative; regnative *pNative = new regnative;
pNative->amx = amx; pNative->amx = amx;
pNative->func = idx; pNative->func = idx;
pNative->caller = NULL;
//we'll apply a safety buffer too //we'll apply a safety buffer too
//make our function //make our function

View File

@ -50,9 +50,7 @@ struct regnative
String name; String name;
char *pfn; char *pfn;
int func; int func;
AMX *caller;
int style; int style;
cell params[CALLFUNC_MAXPARAMS];
}; };
extern "C" void amxx_DynaInit(void *ptr); extern "C" void amxx_DynaInit(void *ptr);

View File

@ -0,0 +1,31 @@
#include <amxmodx>
native Factorial(num)
public __Factorial(id, num)
{
new num = get_param(1)
if (num == 0)
{
return 1
}
return num * Factorial(num - 1)
}
public plugin_natives()
{
register_native("Factorial", "__Factorial")
}
public plugin_init()
{
register_plugin("Native Test", "1.0", "BAILOPAN")
register_srvcmd("test_native1", "Command_TestNative1")
}
public Command_TestNative1()
{
new num = Factorial(6)
server_print("Factorial of 6 is: %d", num)
}