]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - hook.c
Fix crash when using +map on cmdline by starting video before parsing configs
[xonotic/darkplaces.git] / hook.c
1 /*
2 Copyright (C) 2020 Cloudwalk
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20
21 #include "quakedef.h"
22 #include "hook.h"
23
24 mempool_t *hooks;
25
26 hook_t *_Hook_Register(hook_t *hook, const char *name, void *func, unsigned int argc)
27 {
28         if (hook) {
29                 Con_Printf("Hook %s already registered\n",hook->name);
30         } else {
31                 hook = (hook_t *)Mem_Alloc(hooks, sizeof(hook_t));
32                 hook->name = Mem_Alloc(hooks, strlen(name) + 1);
33                 hook->arg = Mem_Alloc(hooks, sizeof(hook_val_t) * argc);
34
35                 memcpy(hook->name, name, strlen(name) + 1);
36                 hook->func = func;
37                 hook->argc = argc;
38         }
39         return hook;
40 }
41
42 // Needs NULL pad to know when va_list ends.
43 hook_val_t *_Hook_Call(hook_t *hook, ... )
44 {
45         uintptr_t arg_ptr; // Align to platform size
46         va_list arg_list;
47         unsigned int i = 0;
48
49         if(!hook)
50                 return (hook_val_t *)NULL;
51
52         va_start(arg_list, hook);
53
54         arg_ptr = va_arg(arg_list,intptr_t);
55
56         if((void *)arg_ptr && !hook->argc)
57                 goto overflow;
58
59         // Loop until we encounter that NULL pad, but stop if we overflow.
60         while ((void *)arg_ptr != NULL && i != hook->argc)
61         {
62                 if (i > hook->argc)
63                         goto overflow;
64                 hook->arg[i].val = arg_ptr;
65                 arg_ptr = va_arg(arg_list,intptr_t);
66                 i++;
67         }
68
69         va_end(arg_list);
70
71         // Should be fairly obvious why it's bad if args don't match
72         if(i != hook->argc)
73                 goto underflow;
74         // Call it
75         hook->ret.uval = (uintptr_t)hook->func(hook->arg);
76         
77         if (hook->ret.val)
78                 return &hook->ret;
79         return (hook_val_t *)NULL;
80
81 underflow:
82         Sys_Error("Hook_Call: Attempt to call hook '%s' with incorrect number of arguments. Got %i, expected %i\n", hook->name, i, hook->argc);
83 overflow:
84         Sys_Error("Hook_Call: Stack overflow calling hook '%s' (argc = %u)\n", hook->name, hook->argc);
85
86 }
87
88 void Hook_Init(void)
89 {
90         hooks = Mem_AllocPool("hooks",0,NULL);
91         return;
92 }