Created
December 17, 2016 18:16
-
-
Save Yiin/4fe4f51b380e2fb184a56a11f85347fe to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
stock bool:Callback_Get(callback:name, ret[E_CALLBACK_DATA], expect[] = "", bool:remote = false) | |
{ | |
P:2("Callback_Get called: %s", name); | |
Inline_Reset(ret); | |
if (!(callback_tag:0 < name[0] < callback_tag:128)) | |
{ | |
P:3("Callback_Get: Found resolved callback."); | |
// Resolved inline. | |
return bool:memcpy(_:ret[E_CALLBACK_DATA:0], name[0], 0, _:E_CALLBACK_DATA * 4, _:E_CALLBACK_DATA); | |
} | |
else if (name[0] == callback_tag:'\03') | |
{ | |
// This prefix is ALWAYS for publics not inlines. | |
return bool:(ret[E_CALLBACK_DATA_POINTER] = (remote ? GetRemoteFunction(name[1], expect) : GetLocalFunction(name[1], expect))); | |
} | |
else if (remote) | |
{ | |
// "remote" functions must always be done this way. | |
return bool:(ret[E_CALLBACK_DATA_POINTER] = GetRemoteFunction(name, expect)); | |
} | |
new | |
pos = strfind(name, "\02"), | |
frm = GetCurrentFramePreviousFrame(), | |
prf = GetFramePreviousFrame(frm); | |
if (pos == -1) | |
{ | |
new | |
cur = YSI_g_sPrevInlineFunc, | |
parent = GetFrameFunction(prf), | |
res; | |
pos = strlen(name), | |
frm = GetFrameReturn(frm); | |
// Find the function by name. | |
while (cur) | |
{ | |
#emit PUSH.S pos | |
#emit PUSH.C 0 | |
#emit PUSH.S name | |
#emit PUSH.S cur | |
#emit PUSH.C 16 | |
#emit SYSREQ.C strcmp | |
#emit STACK 20 | |
#emit STOR.S.pri res | |
if (res == 0 && AMX_Read(cur + pos * 4) == '\02') | |
{ | |
if (parent <= AMX_Read(cur + pos * 4 + 1 * 4) <= frm) | |
{ | |
// Rewrite the value of "name" for the subsequent code. | |
#emit LOAD.S.pri cur | |
#emit STOR.S.pri name | |
break; | |
} | |
} | |
static const | |
gsSearch[] = "\02"; | |
#emit PUSH.C 0 | |
#emit PUSH.C 0 | |
#emit PUSH.C gsSearch | |
#emit PUSH.S cur | |
#emit PUSH.C 16 | |
#emit SYSREQ.C strfind | |
#emit STACK 20 | |
#emit LOAD.S.alt cur | |
#emit IDXADDR | |
#emit ADD.C 16 | |
#emit LOAD.I | |
#emit STOR.S.pri cur | |
} | |
if (!cur) | |
{ | |
// Try publics... | |
return bool:(ret[E_CALLBACK_DATA_POINTER] = GetLocalFunction(name, expect)); | |
} | |
} | |
static | |
spec[2]; | |
Inline_EncodeFormatString(expect, spec), | |
ret[E_CALLBACK_DATA_FORMAT] = spec, | |
// Load this inline function's data in to our closure (and allocate memory). | |
ret[E_CALLBACK_DATA_POINTER] = Function:name[pos + 1]; | |
new | |
to = name[pos + 2], | |
local = to >> 8, // Sign-extending! | |
params = to & 0xFF, | |
stack = params + local + 3, | |
Alloc:a = malloc(stack); // Allocate closure space. | |
// printf("local: %d, params: %d, stack: %d", local, params, stack); | |
if (a) | |
{ | |
// Get the address of the data. | |
#emit CONST.alt YSI_gMallocMemory | |
#emit LOAD.S.pri a | |
#emit IDXADDR | |
#emit STOR.S.pri frm | |
// Get the stack size in bytes. | |
stack <<= 2, | |
ret[E_CALLBACK_DATA_ALLOC] = ResolvedAlloc:frm, | |
ret[E_CALLBACK_DATA_OFFSET] = stack, | |
// Copy the stack over. First get the frame of the function that used | |
// an inline function, thus calling us indirectly. | |
prf -= local << 2, | |
// Adjust to the bottom of that stack, at least the bottom of the parts | |
// we need (there may be more locals declared later that we don't need). | |
// Copy "stack" bytes from "prf" to "frm". | |
rawMemcpy(frm, prf, stack), | |
// Save the "return" address for the inline to our fake stack. | |
mset(a, local + 1, name[pos + 3]), | |
// Save the parameter count (may be mangled by y_hooks). | |
mset(a, local + 2, params << 2); | |
P:2("Callback_Get end"); | |
return true; | |
} | |
return false; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment