+/*
+Copyright (C) 2020 Cloudwalk
+
+This program 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 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "quakedef.h"
+#include "hook.h"
+
+mempool_t *hooks;
+
+hook_t *_Hook_Register(hook_t *hook, const char *name, void *func, unsigned int argc)
+{
+ if (hook) {
+ Con_Printf("Hook %s already registered\n",hook->name);
+ } else {
+ hook = (hook_t *)Mem_Alloc(hooks, sizeof(hook_t));
+ hook->name = Mem_Alloc(hooks, strlen(name) + 1);
+ hook->arg = Mem_Alloc(hooks, sizeof(hook_val_t) * argc);
+
+ memcpy(hook->name, name, strlen(name) + 1);
+ hook->func = func;
+ hook->argc = argc;
+ }
+ return hook;
+}
+
+// Needs NULL pad to know when va_list ends.
+hook_val_t *_Hook_Call(hook_t *hook, ... )
+{
+ uintptr_t arg_ptr; // Align to platform size
+ va_list arg_list;
+ unsigned int i = 0;
+
+ if(!hook)
+ return (hook_val_t *)NULL;
+
+ va_start(arg_list, hook);
+
+ arg_ptr = va_arg(arg_list,intptr_t);
+
+ if((void *)arg_ptr && !hook->argc)
+ goto overflow;
+
+ // Loop until we encounter that NULL pad, but stop if we overflow.
+ while ((void *)arg_ptr != NULL && i != hook->argc)
+ {
+ if (i > hook->argc)
+ goto overflow;
+ hook->arg[i].val = arg_ptr;
+ arg_ptr = va_arg(arg_list,intptr_t);
+ i++;
+ }
+
+ va_end(arg_list);
+
+ // Should be fairly obvious why it's bad if args don't match
+ if(i != hook->argc)
+ goto underflow;
+ // Call it
+ hook->ret.uval = (uintptr_t)hook->func(hook->arg);
+
+ if (hook->ret.val)
+ return &hook->ret;
+ return (hook_val_t *)NULL;
+
+underflow:
+ Sys_Error("Hook_Call: Attempt to call hook '%s' with incorrect number of arguments. Got %i, expected %i\n", hook->name, i, hook->argc);
+overflow:
+ Sys_Error("Hook_Call: Stack overflow calling hook '%s' (argc = %u)\n", hook->name, hook->argc);
+
+}
+
+void Hook_Init(void)
+{
+ hooks = Mem_AllocPool("hooks",0,NULL);
+ return;
+}
\ No newline at end of file